【问题标题】:drag and drop in android 3.x causes illegalStateException after small number on drags在 android 3.x 中拖放会在少量拖动后导致非法状态异常
【发布时间】:2012-03-22 22:59:39
【问题描述】:

android 3.x 的拖放机制存在问题: 在做了一些拖拽(比如 30 次拖拽)后,会产生异常(请参阅所附链接)

https://groups.google.com/forum/#!msg/android-platform/2APvO248NNY/rKI-5dCT8XcJ (我正在登录与该帖子所附内容相同的内容..)

android 技术人员在那里回答说这是 API 中的错误,并说避免该问题的唯一方法是调用垃圾收集器。

我做到了。不再抛出异常,但一段时间后(比如多拖 30-40 次)android 由于某种原因停止调用 drop 事件。

我试图通过释放所有资源/画布/绘图缓存/回收位图并重新创建它们来“刷新”所有视图,但它没有帮助(不再抛出异常 - 但在一些拖放之后仍然存在事件不起作用)

“帮助”的唯一方法是关闭活动并重新启动它。

有人以某种方式解决了这个问题,或者有一个很好的简单替代方案??? (除了实现我自己的拖放功能..)

我想获得不会强迫我重新启动或重新创建任何不应该这样做的解决方案..

这里是演示错误的示例代码(不演示我所说的关于使用 System.GC 后 drop 事件问题的部分):

public class DragandDropExampleActivity extends Activity {

private boolean mIsBeenDragged = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final ImageView imageViewToDRag = (ImageView) findViewById(R.id.image_view_to_drag);

    imageViewToDRag.setClickable(true);

    imageViewToDRag.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                mIsBeenDragged = true;
                DragShadowBuilder shadowBuilder = new DragShadowBuilder(imageViewToDRag);
                imageViewToDRag.startDrag(null, shadowBuilder, imageViewToDRag, 0);
            } else if (event.getAction() == MotionEvent.ACTION_UP) {

                mIsBeenDragged = false; 
            }
            return false;
        }
    });

}
}

这是xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >

<ImageView
    android:id="@+id/image_view_to_drag"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_launcher" >

</ImageView>

这是堆栈跟踪:

06-04 13:34:32.730: E/View(8061):
java.lang.IllegalArgumentException
    at android.view.Surface.lockCanvasNative(Native Method)
    at android.view.Surface.lockCanvas(Surface.java:350)
    at android.view.View.startDrag(View.java:11489)
    at com.show.dragandrop.DragandDropExampleActivity$1.onTouch(DragandDropExampleActivity.java:32)
    at android.view.View.dispatchTouchEvent(View.java:4617)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1560)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1291)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1560)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1291)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1560)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1291)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1560)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1291)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java: 1862)
    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1286)
    at android.app.Activity.dispatchTouchEvent(Activity.java:2315)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1835)
    at android.view.View.dispatchPointerEvent(View.java:4689)
    at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2415)
    at android.view.ViewRoot.handleMessage(ViewRoot.java:2077)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:132)
    at android.app.ActivityThread.main(ActivityThread.java:4126)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
    at dalvik.system.NativeStart.main(Native Method)

要产生异常 - 只需将图像拖动到屏幕上的某个点,然后离开手指。重复 30 次,然后抛出异常。 我做了这个非常简单的例子,来证明我的应用程序在没有任何开销的情况下抛出了异常。

TIA

【问题讨论】:

  • 你能添加一些示例代码来玩吗?我认为这与取消的活动有关。对象处于无效状态的位置。
  • 是的,我可以,但我目前不在我的工作站,所以我会在明天发布..谢谢
  • @rekire:我已经添加了代码。等着看你会想出什么。顺便说一句 - 在模拟器上不会抛出异常
  • @TalKanel 太糟糕了,我没有合适的设备。反正我会看看的。
  • 这对您有什么帮助吗? stackoverflow.com/questions/8875702/…

标签: android view drag-and-drop touch-event illegalstateexception


【解决方案1】:

试试这个:-

private OnTouchListener drag = new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            setViewPosition(v, Math.round(event.getRawX()),
                    Math.round(event.getRawY()));
        }
        return false;
    }
};


private void setViewPosition(View v, int x, int y) {
    if (v != null) {
        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT);
        params.leftMargin = (x - v.getMeasuredWidth() / 2);
        params.topMargin = (y - v.getMeasuredHeight() / 2);
        v.setLayoutParams(params);
        v.invalidate();
    }
}

【讨论】:

    【解决方案2】:

    如果重新启动活动有帮助,请尝试重新启动视图,将其删除并再次添加(可能是新实例)。您也可以尝试像 invalidate() 这样的普通人员(通常没有帮助),覆盖 onDraw() 并查看为什么调用或不调用它。

    【讨论】:

    • 不错的想法,但如果不够清楚 - 我也尝试过,但没有帮助。无论如何 - 我想要一个不强迫我重新启动/删除任何东西的解决方案......
    【解决方案3】:

    试试这个:

    imageViewToDRag.startDrag(null, shadowBuilder, imageViewToDRag, 0);
    System.gc();
    

    它在 Android 3.2 上对我有用!

    【讨论】:

    • 已经试过了。我在问题的正文上写了它。在简单的演示应用程序上它可以解决问题 - 但是当我多次使用它时,拖动事件会在一段时间后停止调用。这也不是一个真正的解决方案调用 GC..
    【解决方案4】:

    来自question 上的comment,其中涉及您在 Google 网上论坛讨论中发布的问题:

    出现此问题是因为 GC 不执行拖动收集。但是如果窗口重绘,GC 会执行拖拽收集。打开软键盘或更新一些 ImageView 或类似的东西后,窗口将被重绘。

    所以听起来你可以通过强制重绘包含View 来让垃圾收集器收集拖动对象。我手边没有 3.0 设备,但也许这样的东西值得一试:

            } else if (event.getAction() == MotionEvent.ACTION_UP) {
               findViewById(R.id.main_frame).invalidate();
            }
    

    您可能还需要建议的垃圾收集提示:

            } else if (event.getAction() == MotionEvent.ACTION_UP) {
               findViewById(R.id.main_frame).invalidate();
               System.gc();
            }
    

    但我认为您希望尽可能避免这种情况是正确的,所以我只会在没有它的情况下尝试这样做。

    另外,我认为onTouch() 应该返回true,因为你已经消费了触摸事件。

    【讨论】:

      【解决方案5】:

      自从我问这个问题以来已经过去了很多时间。 当 android ICS 发布时 - 这个错误不再存在。 因此,自从 android ICS 以来,确实没有理由编写针对 Honeycomb 的应用程序。 无论如何,只有 0.3% 的 Android 设备运行此版本的操作系统,

      所以对我来说答案是 - 只是不要使用 Honeycomb! :->

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-03-14
        • 1970-01-01
        • 1970-01-01
        • 2015-11-13
        • 2017-12-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多