0

Android 애플리케이션 용 XMPP 클라이언트를 구현 중입니다. 나에게 보낸 채팅 메시지를 얻으려면 Smack에서 PacketListener를 사용하고있다. 응용 프로그램의 XMPP 부분을 사용하면 모든 것이 잘 동작합니다. 나는 메시지를 보내고받을 수있다. 하지만받은 메시지를 표시하는 데 문제가 있습니다.Android : PacketListener 작업자 스레드에서 ArrayAdapter/ListView 업데이트

메시지를 표시하기 위해 내 응용 프로그램은 ListAdapter에 바인딩하는 ArrayAdapter를 사용합니다. 어댑터 자체는 문제없이 전송 한 메시지를 표시하므로 정상적으로 작동합니다. 하지만받은 메시지에는 그렇지 않습니다. UI와의 상호 작용이 발생하는 경우에만 표시됩니다. 분명히 이것은 스레딩 문제입니다.

Javadoc과 디버거에서 나에게 말한 것과 틀린 부분이 없다면 PacketListener.processPacket() 메서드는 자체 스레드에서 실행되고 Handler에 다음 작업이있는 경우에만 ListView 업데이트가 실행됩니다. 그렇게하고 처리한다. 내 질문은 지금, 처리기 즉시 처리하도록 어떻게 말할 수 있습니까? 이 작업자 스레드와 기본 스레드 간의 통신은 어떻게 작동합니까? Runnable을 직접 만들지 않았으므로 어떻게 처리해야할지 모르겠다. 당신이 당신의 UI 스레드 내에서 Handler를 만들 경우 당신이 당신의 displayMessage() 방법을 호출하는 Runnable 인수로에 post()를 호출 할 수

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

답변

0

:

그리고 여기에 코드입니다. 또는 Activity 클래스의 일부인 runOnUiThread()을 다시 호출하여 을 호출하고 displayMessage()을 호출 할 수 있습니다.

onClick() 처리기에서 sendPacket()으로 전화를 걸었습니다. UI 스레드를 차단하지 않아야합니다. 아마 sendPacket() 실제로 실제 보내기를 수행하는 새 스레드를 생성 할 것입니다,하지만 당신이 확인해야합니다.

0

코드를 다음과 같이 수정했습니다. 이제 문제없이 사용할 수 있습니다.

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

    }