Android:从 PacketListener 工作线程内更新 ArrayAdapter / ListView

发布于 2024-11-30 22:25:46 字数 2628 浏览 1 评论 0原文

我正在为 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

输什么也不输骨气 2024-12-07 22:25:46

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

我还注意到您从 onClick() 处理程序调用 sendPacket() 。您应该确保不会阻塞 UI 线程。也许 sendPacket() 实际上会生成一个新线程来执行实际发送,但您应该检查一下。

If you create a Handler within your UI thread, you can call post() on it with a Runnable argument that calls your displayMessage() method. Alternatively, you can call runOnUiThread(), which is part of the Activity class, again, passing a Runnable that calls displayMessage().

I've also noticed that you call sendPacket() from your onClick() handler. You should make sure that you don't block the UI thread. Maybe sendPacket() will actually spawn a new thread to do the actual send, but it's something that you should check.

年少掌心 2024-12-07 22:25:46

我修改了你的代码如下。希望它现在可以工作。

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();
                 }
             }
        }

    }

I modified your code as follows.Hope it will work now.

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();
                 }
             }
        }

    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文