Android:从packketlistener工作线程中更新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();
    }
}

如果你在UI线程中创建了一个Handler,你可以用Runnable参数调用displayMessage()方法来调用post()。或者,您可以调用runOnUiThread(),它是Activity类的一部分,再次传递调用displayMessage()Runnable

我还注意到您从onClick()处理程序调用sendPacket()。你应该确保你没有阻塞UI线程。也许sendPacket()实际上会生成一个新线程来完成实际的发送,但这是你应该检查的东西。

我将您的代码修改如下:希望它现在能起作用。

public class Chat extends Activity {
        private ArrayList<String> mMessages;
        private ArrayAdapter<String> mAdapter;
        private ListView mMessageListView;
        private EditText mInput;
        private String mRecipient;
        String chat;
        @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);
                    String sender = message.getFrom();
                    chat = sender + " > " + message.getBody();
                    Message msg = handler.obtainMessage();
                    msg.arg1 = 1;
                    handler.sendMessage(msg);
                }
            }, 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();
        }
        private final Handler handler = new Handler() {
            public void handleMessage(Message msg) {
                 if(msg.arg1 == 1){
                     mAdapter.add(chat);
                     mAdapter.notifyDataSetChanged();
                 }
             }
        }
    }

最新更新