Android Handler消息和ListView

我现在为LONG发帖道歉,但这是我唯一可以解释的方式,而google给出了3页的结果并不确凿

这是我的错误家伙:

*** Uncaught remote exception! (Exceptions are not yet supported across processes.) android.util.AndroidRuntimeException: { what=1008 when=368280372 } This message is already in use. at android.os.MessageQueue.enqueueMessage(MessageQueue.java:171) at android.os.Handler.sendMessageAtTime(Handler.java:457) at android.os.Handler.sendMessageDelayed(Handler.java:430) at android.os.Handler.sendMessage(Handler.java:367) at android.view.ViewRoot.dispatchAppVisibility(ViewRoot.java:2748) 

我正在尝试的是有一个列表视图,由自定义列表项目填充,每个列表项目有多个视图,每个视图都有一个onclick监听器附加。 当这个onClickListener被按下时,它发送一个消息给一个具有what和arg1参数的处理器。 点击我的其中一个元素激发了开始新活动的意图。 点击另一个显示敬酒。 当这些组合按下时,我得到上面的错误。 即点击文本来激发意图(然后按回),然后点击图片显示烤面包,然后当你点击文本再次激发意图时,我得到了FC。

我创build了一个演示项目,重现了这个: http : //rapidshare.com/files/429227042/HandlerTest.rar

这里是下面的代码,我试图去除尽可能多的残留物,以达到错误的骨骼:

如果您想跳过ConversationAdapter.class中的onClickListener,以及它们如何与StartPage.class交互

Android清单:

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.handler.test" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".StartPage" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".DetailsPage" android:label="DetailsPage" > </activity> </application> <uses-sdk android:minSdkVersion="3" /> </manifest> 

StartPage.class:

 package com.handler.test; import java.util.ArrayList; import android.app.ListActivity; import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.widget.Toast; public class StartPage extends ListActivity { private ArrayList<Conversation> mConversations = null; private ConversationAdapter mAdapter; private Context mContext; private ProgressDialog mProgressDialog; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mContext = this; mConversations = new ArrayList<Conversation>(); this.mAdapter = new ConversationAdapter(mContext, R.layout.inbox_row, mConversations, mHandler); setListAdapter(this.mAdapter); new Thread(new Runnable() { @Override public void run() { getConversations(); } }).start(); mProgressDialog = ProgressDialog.show(StartPage.this, "Please wait...", "Retrieving data ...", true); } private void getConversations() { try { mConversations = new ArrayList<Conversation>(); Conversation o1 = new Conversation(); o1.setStatus("SF services"); o1.setMessage("Pending"); mConversations.add(o1); } catch (Exception e) { Log.e("BACKGROUND_PROC", e.getMessage()); } runOnUiThread(returnRes); } private Runnable returnRes = new Runnable() { @Override public void run() { if(mConversations != null && mConversations.size() > 0){ mAdapter.notifyDataSetChanged(); for(int i=0;i<mConversations.size();i++) mAdapter.add(mConversations.get(i)); } mProgressDialog.dismiss(); mAdapter.notifyDataSetChanged(); } }; private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { int convIndex = msg.arg1; int viewTouched = msg.what; switch(viewTouched){ case ConversationAdapter.PROF_ICON: showNumber(convIndex); break; case ConversationAdapter.MESSAGE: showMessageDetails(convIndex); break; } super.handleMessage(msg); } }; private void showNumber(int convIndex) { Toast.makeText(mContext, "Pressed: "+convIndex, Toast.LENGTH_LONG).show(); } private void showMessageDetails(int convIndex) { final Conversation conv = mConversations.get(convIndex); Intent i = new Intent(mContext, DetailsPage.class); i.putExtra("someExtra", conv); startActivity(i); } } 

DetailsPage.class

 package com.handler.test; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class DetailsPage extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.i("Test", "Details Page"); } } 

Conversation.class:

 package com.handler.test; import java.io.Serializable; public class Conversation implements Serializable { private static final long serialVersionUID = -437261671361122258L; private String status; public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } 

ConversationAdapter.class:

 package com.handler.test; import java.util.ArrayList; import android.content.Context; import android.os.Handler; import android.os.Message; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.LinearLayout; public class ConversationAdapter extends ArrayAdapter<Conversation> { public static final int PROF_ICON = 0; public static final int MESSAGE = 1; private Context mContext; private Handler mHandler; private ArrayList<Conversation> mItems; private int mXmlId; private LinearLayout detailsOfConv; private ImageView iconImage; public ConversationAdapter(Context context, int textViewResourceId, ArrayList<Conversation> items, Handler handler) { super(context, textViewResourceId, items); this.mContext = context; this.mItems = items; this.mXmlId = textViewResourceId; this.mHandler = handler; } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(mXmlId, null); } final Message m = new Message(); m.arg1 = position; Conversation c = mItems.get(position); if (c != null) { iconImage = (ImageView) v.findViewById(R.id.icon); if (iconImage != null) { iconImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { m.what = PROF_ICON; mHandler.sendMessage(m); } }); } detailsOfConv = (LinearLayout) v.findViewById(R.id.details); if(detailsOfConv != null){ detailsOfConv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { m.what = MESSAGE; mHandler.sendMessage(m); } }); } } return v; } } 

main.xml中:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dip" > <ListView android:id="@+id/android:list" android:layout_width="wrap_content" android:layout_height="wrap_content" android:cacheColorHint="#00000000" /> </LinearLayout> 

inbox_row.xml:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:padding="6dip"> <ImageView android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_marginRight="6dip" android:src="@drawable/icon" /> <LinearLayout android:id="@+id/details" android:orientation="vertical" android:layout_width="0dip" android:layout_weight="1" android:layout_height="fill_parent"> <TextView android:id="@+id/toptext" android:textColor="#99FF66" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" android:singleLine="true" android:text="123456789" /> </LinearLayout> </LinearLayout> 

对不起所有的代码!

Solutions Collecting From Web of "Android Handler消息和ListView"

我的猜测是你发送两次相同的信息。 事实上,在代码中有一个new Message()和两个mHandler.sendMessage(m) ,它们都可能被执行。

尝试每次发送消息时都要发送一条新消息。

编辑:

Message.obtain()比Message m = new Message()更好(因为它在引擎盖下回收使用的消息)

在你的情况下,如果你需要一个现有的消息的副本,你可以使用new.copyFrom(旧) 。