很抱歉,如果我犯了任何愚蠢的错误,但是我找不到此信息的来源:
我正在尝试在我的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
,但是很显然,该框架调用了所有子级View
的OnDragEvent()
回调,如在崩溃堆栈跟踪中所示。
崩溃发生在内部类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()
中的原始代码做什么,跳过它似乎都不会影响我的个人用例,并且我也没有发现我需要的任何功能。