很抱歉,如果我犯了任何愚蠢的错误,但是我找不到此信息的来源:
我正在尝试在我的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;
            }});


这在我的Samsng Galaxy Grand上运行正常,但是在Nexus上给了我一个空指针。

stackTrace:

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

最佳答案

我认为这是EditText小部件和Android中的拖放API的错误。我在其他解决方案中链接的问题跟踪器中添加了一个帖子,但是为了便于阅读,我将在此处进行复制。如果您遇到此问题,请please go to the tracker并加注星标,以期使Android工程师意识到这一点(我想是如意算盘)。

撞车原因

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

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

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中建议的解决方法类似,您可以在将接收拖动事件的View层次结构中的OnDragListener对象上设置虚拟EditText。但是,虚拟侦听器可以只是

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


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

不必为该虚拟侦听器的注释#1看到单独的(event.getAction() == DragEvent.ACTION_DROP)条件,因为如果您为ACTION_DRAG_STARTED返回false,则无论如何都不会收到ACTION_DROP事件(您可以通过放置ACTION_DROP条件下的日志打印消息,您会发现它从未被调用,因为您已经在false条件下返回了else

第二种解决方法:*编辑(请参见下文)

由于在尝试访问null中的ClipData Editor.onDrop()时会发生NPE,因此在开始拖动过程​​时,只需向ClipData提供一个虚拟DragEvent

这是我针对自己的情况做的事情:

... <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,因为您不能仅使用其构造函数和ClipData参数构造一个null,因为这也会导致崩溃。

因此,无论在哪里使用View.startDrag()开始拖动过程​​,请确保提供此虚拟ClipData。通过这种解决方法,我不需要虚拟OnDragListener,也不会出现NPE崩溃。

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

*编辑:在使用EditText小部件进行拖放操作时,我发现TextView.onDragEvent()确实存在一些奇怪的行为,如果您采用第二种解决方法,最终会被称为。我注意到,当使用我建议的虚拟ClipData时,如果您尝试将窗口小部件拖动到ClipData.newPlainText()的第二个参数中,则传递给您的“ dummyData”字符串有时会粘贴/插入到EditText中。同时在文本框中移动插入符号,或通过键入EditText然后将其拖动到位。

解释起来很混乱,但是我能够可靠地重现它。如果想尝试并理解它,任何读者都可以take a look at the source code尝试使用该方法,但是老实说,我厌倦了试图找出Android工程师对此的奇怪意图。由于这种奇怪的行为,我更改了第二个解决方法,改为传递一个空String作为第二个参数。这似乎减轻了问题。

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

10-08 20:22