Android:从 PacketListener 工作线程内更新 ArrayAdapter / ListView
我正在为 Android 应用程序实现 XMPP 客户端。为了获取发送给我的聊天消息,我使用了 Smack 的 PacketListener。使用应用程序的 XMPP 部分,一切正常。我可以发送和接收消息。但我在显示收到的消息时遇到问题。
为了显示消息,我的应用程序使用 ArrayAdapter 将消息绑定到 ListView。适配器本身工作正常,因为它显示我发送的消息没有任何问题。但收到的消息却并非如此。仅当与 UI 发生某些交互时才会显示它们。显然,这是一个线程问题。
如果我没有误解 Javadoc 和调试器告诉我的内容,PacketListener.processPacket() 方法在自己的线程中运行,并且仅当处理程序有下一步要做并因此处理时才会执行 ListView 的更新它。现在我的问题是,如何告诉Handler立即处理它?这里这个工作线程和主线程的通信是如何进行的呢?由于我自己没有制作Runnable,所以我不知道如何处理这个问题。
这是代码:
public class Chat extends Activity {
private ArrayList<String> mMessages;
private ArrayAdapter<String> mAdapter;
private ListView mMessageListView;
private EditText mInput;
private String mRecipient;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat);
Bundle extras = getIntent().getExtras();
mRecipient = extras.getString("jabberid");
mMessages = new ArrayList<String>();
mMessageListView = (ListView) findViewById(R.id.chatMessageList);
mInput = (EditText) findViewById(R.id.chatInput);
mAdapter = new ArrayAdapter<String>(this, R.layout.channelentry, mMessages);
mAdapter.notifyDataSetChanged();
mMessageListView.setAdapter(mAdapter);
// Getting messages
PacketFilter packetFilter = new MessageTypeFilter(Message.Type.chat);
// XMPPConnection already connected and authenticated
XmppManager.connection.addPacketListener(new PacketListener() {
// Here is where it doesn't display the received message
@Override
public void processPacket(Packet packet) {
Message message = (Message) packet;
displayMessage(message);
}
}, packetFilter);
// Sending messages
Button send = (Button) findViewById(R.id.chatSend);
send.setOnClickListener(new View.OnClickListener() {
// Here everything works just fine
@Override
public void onClick(View v) {
Message message = new Message(mRecipient, Message.Type.chat);
message.setBody(mInput.getText().toString());
XmppManager.connection.sendPacket(message);
displayMessage(message);
}
});
}
private void displayMessage(Message message) {
String sender = message.getFrom();
String chat = sender + " > " + message.getBody();
mAdapter.add(chat);
mAdapter.notifyDataSetChanged();
}
}
I'm implementing XMPP client for an Android application. For getting the chat messages that are sent to me, I'm using the PacketListener from Smack. With the XMPP part of the application, everything works fine. I can send and receive messages. But I'm having problems displaying the received messages.
For displaying messages, my application uses an ArrayAdapter that binds them to a ListView. The adapter itself works fine, since it displays the messages I send without any problems. But not so with the received messages. They are just displayed if some interaction with the UI happens. Apparently, this is a threading issue.
If I'm not mistaken by what the Javadoc and the Debugger tell me, the PacketListener.processPacket() method runs in an own thread, and the update of the ListView is only executed if the Handler has a next thing to do and therefore processes it. My question is now, how can I tell the Handler to process it immediately? How does the communication between this worker thread and the main thread work here? Since I didn't make a Runnable myself, I don't know how to handle this.
And here's the code:
public class Chat extends Activity {
private ArrayList<String> mMessages;
private ArrayAdapter<String> mAdapter;
private ListView mMessageListView;
private EditText mInput;
private String mRecipient;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat);
Bundle extras = getIntent().getExtras();
mRecipient = extras.getString("jabberid");
mMessages = new ArrayList<String>();
mMessageListView = (ListView) findViewById(R.id.chatMessageList);
mInput = (EditText) findViewById(R.id.chatInput);
mAdapter = new ArrayAdapter<String>(this, R.layout.channelentry, mMessages);
mAdapter.notifyDataSetChanged();
mMessageListView.setAdapter(mAdapter);
// Getting messages
PacketFilter packetFilter = new MessageTypeFilter(Message.Type.chat);
// XMPPConnection already connected and authenticated
XmppManager.connection.addPacketListener(new PacketListener() {
// Here is where it doesn't display the received message
@Override
public void processPacket(Packet packet) {
Message message = (Message) packet;
displayMessage(message);
}
}, packetFilter);
// Sending messages
Button send = (Button) findViewById(R.id.chatSend);
send.setOnClickListener(new View.OnClickListener() {
// Here everything works just fine
@Override
public void onClick(View v) {
Message message = new Message(mRecipient, Message.Type.chat);
message.setBody(mInput.getText().toString());
XmppManager.connection.sendPacket(message);
displayMessage(message);
}
});
}
private void displayMessage(Message message) {
String sender = message.getFrom();
String chat = sender + " > " + message.getBody();
mAdapter.add(chat);
mAdapter.notifyDataSetChanged();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您在 UI 线程中创建
Handler
,则可以调用post()
,并使用Runnable
参数调用您的displayMessage()
方法。或者,您可以调用runOnUiThread ()
,它是Activity
类的一部分,同样传递一个调用displayMessage()
的Runnable
。我还注意到您从
onClick()
处理程序调用sendPacket()
。您应该确保不会阻塞 UI 线程。也许sendPacket()
实际上会生成一个新线程来执行实际发送,但您应该检查一下。If you create a
Handler
within your UI thread, you can callpost()
on it with aRunnable
argument that calls yourdisplayMessage()
method. Alternatively, you can callrunOnUiThread()
, which is part of theActivity
class, again, passing aRunnable
that callsdisplayMessage()
.I've also noticed that you call
sendPacket()
from youronClick()
handler. You should make sure that you don't block the UI thread. MaybesendPacket()
will actually spawn a new thread to do the actual send, but it's something that you should check.我修改了你的代码如下。希望它现在可以工作。
I modified your code as follows.Hope it will work now.