【发布时间】:2013-12-09 23:15:15
【问题描述】:
我不确定这是设备问题还是我的代码问题,但我使用相对布局和图像视图创建了一个简单的可拖动排序列表。我这样做有非常具体的原因,这不是我的问题。
我遇到的问题是有时它会完全冻结我的应用程序。该项目将卡在拖动状态。如果我抬起手指,阴影(拖动)对象仍然在屏幕上,如果我触摸屏幕,它会移动到那个位置。这将持续大约一分钟,然后我会收到一条错误消息,说应用程序没有响应,可以选择杀死它或等待。 logcat中唯一有用的位如下:
12-09 14:23:13.157: W/WindowManager(16415): Drag is in progress but there is no drag window handle.
然后当应用程序超时时,我将其视为错误
12-09 14:59:09.782: E/ActivityManager(16415): ANR in com.appname.appname (com.appname.appname/.MainActivity)
12-09 14:59:09.782: E/ActivityManager(16415): Reason: keyDispatchingTimedOut
我用谷歌搜索了这条错误消息,唯一的信息是有人没有拖动监听器,而另一个人说这是设备触摸传感器跟不上。
理想情况下,我很乐意修复此错误并从一开始就防止它发生。如果我快速拖动似乎确实会发生这种情况,但我不能很好地要求我的用户不要快速拖动......对吗?
或者,有没有一种方法可以检测到拖动已冻结应用程序并中断拖动。就像在触摸监听器上设置一个计时器,如果在一两秒内没有 drag_location 消息中断拖动?计时器的东西我知道该怎么做,但我不知道如何在它冻结时强制拖动停止。有什么想法吗?
代码如下:
设置
//happens once when the app loads
RelativeLayout trackList = (RelativeLayout) findViewById(R.id.nsTrackList1);
trackList.setOnDragListener(new MyTrackDragListener(this));
//happens in a loop for each "track" (image view)
trackButton = new ImageView(this);
trackButton.setImageDrawable(nsPackages[trackId].banner[bannerSizeSelector]);
trackButton.setOnTouchListener(new MyTrackTouchListener());
一触即发
public class MyTrackTouchListener implements OnTouchListener {
boolean isDragging=false;
float prevX, prevY;
public boolean onTouch(View view, MotionEvent motionEvent) {
if(motionEvent.getPointerCount() < 2 && !isDragging) return false;
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
isDragging=false;
prevX=0;
prevY=0;
return true;
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
if(isDragging) return true;
boolean wasFirst = (prevX == 0 || prevY == 0);
float theTotalDiff = Math.abs(prevX - motionEvent.getX()) + Math.abs(prevY - motionEvent.getY());
prevX=motionEvent.getX();
prevY=motionEvent.getY();
if(wasFirst) return true;
if(theTotalDiff <3) return true;
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(data, shadowBuilder, view, 0);
int thisViewId = view.getId();
//hide view
view.setVisibility(View.GONE);
isDragging=true;
return true;
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
isDragging=false;
return true;
}else {
Integer thisAction = motionEvent.getAction();
Log.d("looper","Motion action: "+thisAction.toString());
return false;
}
}
}
拖动时
class MyTrackDragListener implements OnDragListener {
public static boolean isDragging=false;
private MainActivity parent;
public MyTrackDragListener(MainActivity myAct){
parent=myAct;
}
@Override
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
isDragging=true;
// do nothing
return true;
case DragEvent.ACTION_DROP:
View view = (View) event.getLocalState();
parent.doDropSort(view,(int) event.getY());
return true;
case DragEvent.ACTION_DRAG_ENDED:
if(isDragging && event.getResult()==false){
View view2 = (View) event.getLocalState();
parent.doDropSort(view2,(int) event.getY(),true);
return true;
}
isDragging=false;
break;
case DragEvent.ACTION_DRAG_LOCATION:
parent.doDragHover((int) event.getY());
return true;
default:
Log.d("looper","drag other... "+String.valueOf(event.getAction()));
}
return false;
}
}
我已经尝试过的一些事情
- 完全移除拖动监听器
- 总是从 onDrag 返回 true
- onDrag 总是返回 false
- 基本上每个组合都在拖动和触摸中返回真/假
- 移除 2 指和 Action_Move 部分并改为触发 Action_down 上的拖动
同样的结果。拖放在大约 70% 的时间里都能完美运行,然后突然出现上述冻结行为。有时它是第一次拖动,有时是几次之后。我注意到除了可能拖动速度之外的一致模式。当我快速拖动时似乎通常会发生这种情况,但拖动方向或拖动到的位置似乎并不重要。
【问题讨论】:
-
作为一名前亚马逊员工和 Kindle 开发人员,我想看看您是否可以通过一个小型测试应用程序对其进行持续复制,然后提交错误报告。
-
@CarlAnderson 谢谢,几天来我一直在尝试手动测试,但看不到任何模式。您对如何为这种行为构建测试应用程序有什么建议吗?有什么方法可以模拟触摸/拖放输入吗?
-
据我所知没有,不幸的是,如果你不能让它持续复制,他们可能不会看它。
-
是的,我就是这么想的。我已经在启动后的第一次拖动中发生了它,而且我还让它让我在它冻结之前对列表进行了几十次排序。这很令人困惑。我试过拖动速度、方向、只有某些项目,但我似乎找不到任何一致性。
-
@CarlAnderson 没有错误,只是我的一个错误。如果我拖动列表中的顶部项目(将其删除),则下面的 Layout Parameter BELOW 设置为它的 ID 的项目会混淆,一切都会分崩离析。
标签: android drag-and-drop imageview android-relativelayout kindle-fire