如何正确地将信息从长时间运行的线程传递到Android中的UI线程?

时间:2016-04-19 18:08:09

标签: android multithreading

我的应用有聊天功能。当我的应用程序首次启动时,我会生成一个侦听器线程来侦听传入的数据:

public class MainActivity extends AppCompatActivity {
    public static LinkedList<Message> chatList;

    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        chatList = new LinkedList<Message>();

        Handler listenerThreadHandler = new Handler();

        MyListener myListener = new MyListener(listenerThreadHandler, MainActivity.this);
        Thread listenerThread = new Thread(myListener);
        listenerThread.start();
    }
}

我的聊天功能是我主要活动中的片段/标签。它有您查看聊天的标准窗口,以及用于发送聊天的EditText和Button:

<LinearLayout android:id="@+id/chat_window" android:orientation="vertical">
    <ListView
        android:id="@+id/received_chats"
        android:stackFromBottom="true"
        android:transcriptMode="alwaysScroll">
    </ListView>
    <LinearLayout android:id="@+id/control_window" android orientation="horizontal">
        <EditText android:id="@+id/chat_entry_window" />
        <Button android:id="@+id/send_chat_button" android:text="Send" />
    </LinearLayout>
</LinearLayout>

当我发送文本时,我将其添加到我的主要LinkedList。

    public class Chat extends Fragment {

    private View rootView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        rootView = inflater.inflate(R.layout.chat, container, false);
        return rootView;
    }

    @Override
    public void onViewCreated(View rootView, Bundle, savedInstanceState){
        super.onViewCreated(rootView, savedInstanceState);
        displayChats();
    }

    @Override
    public void onResume(){
        super.onResume();
        displayChats();
    }

    @Override
    public View getView(){
        Button sendChatButton = (Button) rootView.findViewById(R.id.send_chat_button);
        sendChatButton.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                EditText chatEntryWindow = (EditText) rootView.findViewById(R.id.chat_text_entry);
                // Add the chat to the LinkedList
                MainActivity.chatList.add(chatEntryWindow.getText().toString());
            }
        });
    }

    public void dispalyChats(){
        final ArrayAdapter adapter = new CustomArrayAdapter(getActivity, R.layout.line_of_chat_text, MainActivity.chatList);
        final ListView list = (ListView) rootView.findViewById(R.id.received_chats);
        list.smoothScrollToPosition(list.getCount() - 1);
    }
}

我还在侦听器中将任何传入的聊天添加到应用

public class MyListener implements Runnable {
    Handler myHandler;
    Context myContext;
    public MyListener(Handler myHandler, Context myContext){
        this.myHandler = myHandler;
        this.myContext = myContext;
    }

    @Override
    public void run(){
        listenForChats();
    }

    public listenForChats(){
        // here is where I want to add chats to my main list.
        MainActivity.chatList.add(received_chat);
    }
}

我希望能够做的是将ListenerThread接收的文本传递回要插入LinkedList的UI线程。我知道我需要这样做,因为我经常在我的应用中遇到这个错误:

  

java.lang.IllegalStateException

     

适配器的内容已更改,但listview未收到通知。

     

确保不从后台线程修改适配器的内容,而只是从UI线程修改。

之前我使用过Handler,但我不知道我是否正确使用它。在过去,我已经传递了一个布局元素(例如,TextView,ImageView等),并使用处理程序更新了它。

在我的监听线程中,我改变了

MainActivity.chatList.add(received_chat);

myHandler.post(new Runnable(){
    @Override
    public void run(){
        MainActivity.chatList.add(received_chat);
    }
});

我的聊天记录仍然被添加到主链接列表中,但我不知道它与我最初的做法有什么不同。我怎么知道我是否已成功将数据传递回UI线程?

那么,如何正确地将数据从我的侦听器线程传递到UI线程以添加到LinkedList?

0 个答案:

没有答案