Android: обновление ArrayAdapter / ListView из рабочего потока PacketListener - PullRequest
0 голосов
/ 19 августа 2011

Я реализую XMPP-клиент для приложения Android.Для получения сообщений чата, которые мне отправляют, я использую PacketListener от Smack.С XMPP частью приложения все работает нормально.Я могу отправлять и получать сообщения.Но у меня возникают проблемы с отображением полученных сообщений.

Для отображения сообщений мое приложение использует ArrayAdapter, который связывает их с ListView.Сам адаптер работает нормально, так как он отображает сообщения, которые я отправляю без проблем.Но не так с полученными сообщениями.Они просто отображаются, если происходит какое-либо взаимодействие с пользовательским интерфейсом.Очевидно, это проблема многопоточности.

Если я не ошибаюсь из-за того, что говорят мне Javadoc и отладчик, метод PacketListener.processPacket () запускается в собственном потоке, и обновление ListView выполняетсявыполняется только в том случае, если у обработчика есть следующая задача, и, следовательно, она обрабатывается.Мой вопрос сейчас, как я могу сказать обработчику немедленно обработать его?Как здесь работает связь между этим рабочим потоком и основным потоком?Поскольку я сам не сделал 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();
    }
}

Ответы [ 2 ]

0 голосов
/ 19 августа 2011

Я изменил ваш код следующим образом. Надеюсь, он будет работать сейчас.

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

    }
0 голосов
/ 19 августа 2011

Если вы создаете Handler в своем потоке пользовательского интерфейса, вы можете вызвать post() для него с аргументом Runnable, который вызывает ваш метод displayMessage().Кроме того, вы можете вызвать runOnUiThread(), который является частью класса Activity, снова передавая Runnable, который вызывает displayMessage().

Я также заметил, чтоВы звоните sendPacket() из вашего onClick() обработчика.Вы должны убедиться, что вы не блокируете поток пользовательского интерфейса.Может быть, sendPacket() на самом деле создаст новый поток для фактической отправки, но это то, что вы должны проверить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...