【问题标题】:onDragEvent() throwing nullpointer on NexusonDrag Event() 在 Nexus 上抛出空指针
【发布时间】:2014-03-26 16:18:49
【问题描述】:

如果我犯了任何愚蠢的错误,我很抱歉,但我找不到这个的来源: 我正在尝试在我的 EditText“etItem”上实现一个 onDrag 侦听器 这是我的代码:

 etItem.setOnDragListener(new OnDragListener(){

            @Override
            public boolean onDrag(View v, DragEvent dragevent) {

                if(null!=dragevent && null!=v){

                    if( dragevent.getAction() == DragEvent.ACTION_DROP )
                    {
                      View view = (View) dragevent.getLocalState();
                      ViewGroup owner = (ViewGroup) view.getParent();

                      int itemNum = (Integer) view.getTag();
                      itemAmounts[itemNum] = 0;
                      owner.removeView(view);
                      return true;

                    }
                    }
                return false;
            }});

这在我的三星 Galaxy Grand 上运行良好,但在 Nexus 上给了我一个空指针。

堆栈跟踪:

03-26 15:47:21.185: E/AndroidRuntime(1439): FATAL EXCEPTION: main
03-26 15:47:21.185: E/AndroidRuntime(1439): java.lang.NullPointerException
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.widget.Editor.onDrop(Editor.java:1797)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.widget.TextView.onDragEvent(TextView.java:8350)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.View.dispatchDragEvent(View.java:16375)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1237)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1237)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1237)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1237)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1237)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1237)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1237)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1237)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1237)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewRootImpl.handleDragEvent(ViewRootImpl.java:3838)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewRootImpl.access$600(ViewRootImpl.java:95)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:2999)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.os.Handler.dispatchMessage(Handler.java:99)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.os.Looper.loop(Looper.java:137)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at android.app.ActivityThread.main(ActivityThread.java:5041)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at java.lang.reflect.Method.invokeNative(Native Method)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at java.lang.reflect.Method.invoke(Method.java:511)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
03-26 15:47:21.185: E/AndroidRuntime(1439):     at dalvik.system.NativeStart.main(Native Method)
03-26 15:47:21.345: W/ActivityManager(297):   Force finishing activity com.listcalc.main/.MainActivityFree

【问题讨论】:

    标签: android android-edittext android-event


    【解决方案1】:

    我认为这是 EditText 小部件和 Android 中的拖放 API 的错误。我在另一个解决方案中链接的问题跟踪器中添加了一个帖子,但我将在此处复制它以方便阅读。如果您遇到此问题,请please go to the tracker 并加注星标,希望 Android 工程师能够意识到这一点(我知道这是一厢情愿的想法)。

    崩溃原因

    我在 4.4.2 中遇到了这个崩溃/错误,同时尝试使用拖放 API 在 FrameLayout 中移动 EditText(非常简单的目标)。我的FrameLayout 上只设置了OnDragListener,但显然框架调用了所有子ViewOnDragEvent() 回调,如崩溃堆栈跟踪中所示。

    崩溃发生在内部类android.widget.Editor.onDrop() 中,该方法尝试从传递给该方法的DragEvent 访问ClipData 信息。

    From 4.4.2 source:

    1828    void onDrop(DragEvent event) {
    1829        StringBuilder content = new StringBuilder("");
    1830        ClipData clipData = event.getClipData();
    1831        final int itemCount = clipData.getItemCount();
    1832        for (int i=0; i < itemCount; i++) {
    1833            Item item = clipData.getItemAt(i);
    1834            content.append(item.coerceToStyledText(mTextView.getContext()));
    1835        }
                ....
    

    在第 1830 行中,event.getClipData() 返回 null。然后在第 1831 行 clipData.getItemCount() 将触发 NPE。这似乎只发生在EditText 上,因为他们有一个android.widget.Editor 实例字段,这让我认为这是一个错误/疏忽。

    我为此找到了两种解决方法。

    第一个解决方法:

    与评论 #1 中提出的解决方法类似,您可以在将接收拖动事件的视图层次结构中的 EditText 对象上设置一个虚拟 OnDragListener。但是,虚拟监听器可以简单地是

    myEditText.setOnDragListener( new View.OnDragListener() {
        @Override
        public boolean onDrag( View v, DragEvent event) {
            return true;
        }
    });
    

    只需为所有 Drag 事件返回 true,您将告诉框架您已经处理了该事件,无论 Action 的类型是什么(即您通过调用 event.getAction() 获得的操作)。这意味着您将拦截 Drag 事件,并且不会进一步将其传递给 View 的实际 OnDragEvent() 回调,从而避免我们在堆栈跟踪中看到的崩溃。

    没有必要为 (event.getAction() == DragEvent.ACTION_DROP) 设置单独的条件,如评论 #1 中针对此虚拟侦听器所见,因为如果您为 ACTION_DRAG_STARTED 返回 false,您将永远不会收到 ACTION_DROP 事件(您可以确认通过在ACTION_DROP 条件中放置一条日志打印消息,您会注意到它永远不会被调用,因为您已经在else 条件中返回了false

    第二种解决方法:*EDITED(见下文)

    由于在尝试访问Editor.onDrop() 中的null ClipData 时会发生NPE,因此您可以在开始拖动过程​​时简单地为DragEvent 提供一个虚拟ClipData

    这就是我为我的场景所做的:

    ... <other code>
    ClipData dummyData = ClipData.newPlainText("dummyData", ""); // don't forget to pass empty String
    DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
    v.startDrag(dummyData, shadowBuilder, v, 0);
    ...
    

    我选择使用辅助方法ClipData.newPlainText 为我创建一个简单的纯文本ClipData,因为你不能只用它的构造函数和null 参数构造一个ClipData,因为这会导致崩溃也。

    因此,无论您在哪里开始使用View.startDrag() 进行拖动过程,请务必提供此虚拟ClipData。有了这个解决方法,我不需要虚拟 OnDragListener 并且我没有遇到任何 NPE 崩溃。

    注意:如果您使用第一个解决方法,请知道通过从虚拟 OnDragListener 返回 true,您将有效地阻止 DragEvent 传播到 TextView.onDragEvent(),因此没有任何代码住在里面的会被召唤。我不确定这是否有副作用,但它绝对不是一个空方法。

    *编辑: 在使用更多的 EditText 小部件进行拖放操作后,我发现 TextView.onDragEvent() 有一些非常奇怪的行为,如果你使用它,最终会被调用第二种解决方法。我注意到,当使用我建议的虚拟 ClipData 时,作为第二个参数传递给 ClipData.newPlainText() 的“dummyData”字符串有时会被粘贴/插入到 EditText 中,如果你尝试在文本框中移动插入符号的同时稍微拖动小部件,或者输入EditText,然后再拖动它。

    解释起来非常混乱,但我能够可靠地重现它。任何读者都可以take a look at the source code 获取该方法,如果他们想尝试理解它,但老实说,我已经厌倦了试图弄清楚 Android 工程师对此的奇怪意图。由于这种奇怪的行为,我改变了我的第二个解决方法,改为传递一个空字符串作为第二个参数。这似乎可以缓解这个问题。

    就个人而言,我最终扩展了EditText 类并创建了自己的类,只是将onDragEvent() 覆盖为return true;,而不是调用超类(即TextView.onDragEvent()。这本质上与相同第一个解决方法,但无论如何我都需要扩展EditText 类以添加一些额外的功能。无论TextView.onDragEvent() 中的原始代码做什么,跳过它似乎都不会影响我的个人用例,我不会请注意我需要的任何功能缺失。

    【讨论】:

      【解决方案2】:

      NVM,发现问题。 原来它可能是框架中的一个错误。

      https://code.google.com/p/android/issues/detail?id=21775

      报告与 nexus 相同的问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-07-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-24
        • 2020-11-22
        相关资源
        最近更新 更多