Android Non-UI to UI Thread Communications(Part 1 of 5)

时间:2022-09-04 13:07:19

original:http://www.intertech.com/Blog/android-non-ui-to-ui-thread-communications-part-1-of-5/

ANDROID UI THREAD AND ANR

On the Android platform, applications operate, by default, on one thread.  This thread is called the UI thread.  It is often called that because this single thread displays the user interface and listens for events that occur when the user interacts with the app.

Developers quickly learn that if code running on that thread hogs that single thread and prevents user interaction (for more than 5 seconds), it causes Android to throw up the infamous Android Not Responsive (ANR) error.

Android Non-UI to UI Thread Communications(Part 1 of 5)

Head to the Android Developers sitefor more information and background on this issue.

PROCESSING THREADS UNABLE TO UPDATE THE UI

So how do you prevent ANR?  Your application must create other threads and put long running work on non-UI threads.  There are options on how to accomplish the creation of alternate threads.  You can create and start your own java.lang.Thread.  You can create and start an AsyncTask- Android’s own thread simplification mechanism.  The non-UI thread then handles long running processing – like downloading a file – while the UI thread sticks to displaying the UI and reacting to user events.  Life seems good again.

However, there is a problem in paradise.  Unfortunately, the user interface (UI) cannot be updated by non-UI threads.  For example, after successfully downloading a file, a separate (non-UI) thread can’t show an AlertDialog, update a TextView widget, otherwise make a UI change to indicate the file has been successfully downloaded.  If you attempt to update the UI from a non-UI thread, the application will compile, but you get a CalledFromWrongThreadException thrown from the point your non-UI thread attempts to make the UI change.  As the exception message will inform you, “Only the original thread that created a view hierarchy can touch its views.”

Android Non-UI to UI Thread Communications(Part 1 of 5)

This seems like a catch-22 situation.  If you put long running work on the UI thread, you can get ANR errors.  If you have multiple threads and put long running work on the non-UI threads, those non-UI threads can’t inform the user of what is happening.

MANY NON-UI TO UI THREAD COMMUNICATION OPTIONS

Well, as it turns out, there are several ways to have non-UI threads request updates to the UI through the UI thread.  In fact, in the next posts, I plan to show you five ways to have the non-UI thread send UI update requests to be executed on the UI thread.

  1. Use runOnUiThread( ) method call
  2. Use post( ) method call
  3. Use the Handler framework
  4. Use a Broadcasts and BroadcastReceiver (optionally with LocalBroadcastManager)
  5. Use an AsyncTask’s onProgressUpdate( ) method

As with all options, there are considerations when making a selection from this list.  Much depends on your design decisions about how/where the non-UI thread is created and launched.

Note:  Android usually provides many options when designing/coding your app.  I have provided these 5 approaches, but I encourage other Android developers reading this post to provide additional options (or adjustments/combo solutions, etc.)  Also, please provide your thoughts on pros/cons of each approach.

A SAMPLE APP

In order to demonstrate the options, I have put together a very small app (it was created with a minimum SDK version of 17 and a target SDK of 19).  The app has one activity (one screen), and it consists of two button widgets and a TextView widget.  One button on the UI starts a separate thread (non-UI) and the other button stops the separate thread’s execution.

Android Non-UI to UI Thread Communications(Part 1 of 5)

As long as it is running, the non-UI thread started by the Start button generates a random number and then sleeps for a number of seconds.  This simulates some long running work.  However, the non-UI thread also wants to display each random number it generates back on the UI in the TextView widget.  As you now know, this can only occur by communicating a UI update through the UI thread.

Android Non-UI to UI Thread Communications(Part 1 of 5)

The code for each example will be available with each post – starting with this post.  The critical pieces are in the ShowSomethingActivity class and its DoSomethingThread inner class.

In the ShowSomethingActivity, an OnClickListener is created to react to the Start and Stop buttons being pressed.  When the Start button is pressed, it calls startGenerating() in the ShowSomethingActivity.

 
1
2
3
4
5
6
7
8
9
10
11
12
OnClickListener listener = new OnClickListener() {
  @Override
  public void onClick(View v) {
    if (v == startButton) {
      Log.v(TAG, "Start Service Button clicked");
      ((ShowSomethingActivity) getActivity()).startGenerating();
    } else {
      Log.v(TAG, "Stop Service Button clicked");
      ((ShowSomethingActivity) getActivity()).stopGenerating();
    }
  }
};

The startGenerating method creates the DoSomethingThread (non-UI thread) and starts it running.

 
1
2
3
4
private void startGenerating() {
  randomWork = new DoSomethingThread();
  randomWork.start();
}

The DoSomethingThread inner class extends java.lang.Thread.  Its run( ) method creates the random number with the desire to update the UI’s TextView widget.  The code to update the UI will happen in the publishProgress() method (see commented out code below). This method will be used to hold UI communications and updates involved in the 5 options.

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class DoSomethingThread extends Thread {
  private static final String TAG = "DoSomethingThread";
  private static final int DELAY = 5000; // 5 seconds
  private static final int RANDOM_MULTIPLIER = 10;
 
  @Override
  public void run() {
    Log.v(TAG, "doing work in Random Number Thread");
    while (true) {
      int randNum = (int) (Math.random() * RANDOM_MULTIPLIER);
      // need to publish the random number back on the UI at this point in the code through the publishProgress(randNum) call
      // publishProgress(randNum);
      try {
        Thread.sleep(DELAY);
      } catch (InterruptedException e) {
        Log.v(TAG, "Interrupting and stopping the Random Number Thread");
        return;
      }
    }
  }
}

When the Stop button is pressed, the OnClickListener (shown above) calls stopGenerating in the ShowSomethingActivity.

 
1
2
3
4
5
private void stopGenerating() {
  randomWork.interrupt();
  //next line shows "Generator is off" in the TextView
  updateResults(getString(R.string.service_off));  
}

This causes the DoSomethingThread to be interrupted and stop updating the UI.

OPTION 1- USE THE RUNONUITHREAD() METHOD

Again, the first option I want to cover in communications between the non-UI and UI threads is using the runOnUiThread() method.  You can find this method defined in Android’s Activityclass.

Using, a non-UI thread communicates the desire to request work be run on the UI thread.  This is accomplished under the covers by publishing the requested action to the event queue of the UI thread.  When it can, the UI thread picks up the action message in the event queue and performs the UI change.

In the DoSomethingThread’s publishProgress() method, the activity’s runOnUiThread method is invoked. It is passed a Runnable object containing the UI-updating code. In this case, it contains the code to update the TextView widget through a call to updateResults(text).

 
1
2
3
4
5
6
7
8
9
10
private void publishProgress(int randNum) {
  Log.v(TAG, "reporting back from the Random Number Thread");
  final String text = String.format(getString(R.string.service_msg), randNum);
  runOnUiThread(new Runnable() {
    @Override
    public void run() {
      updateResults(text);
    }
  });
}

Here is the updateResult(text) method in the ShowSomethingActivity.

 
1
2
3
public void updateResults(String results) {
  mainFrag.getResultsTextView().setText(results);
}

So the non-UI thread doesn’t actually update the UI (the TextView widget).  It sends a message via the runOnUiThread() call to the UI event queue.  The runOnUiThread() method is a convenience for completing this messaging operation.  The UI thread watches the event queue and eventually reacts to the request.

The SimpleApp example code for this option can be found here(in an Eclipse project ZIP file).

CONSIDERATIONS OF OPTION 1 – RUNONUITHREAD() METHOD

What are the pros/cons when considering using the runOnUiThread.  First off, note that this method is defined on the Activity.  That means that the non-UI thread must have some knowledge or means of getting the Activity in order to take advantage of this method.  In this example, that is rather easy since the non-UI thread class is defined as an inner class of the Activity.  What happens if the non-UI thread class is defined elsewhere?

You may not be able to see it now, but at the conclusion of the review of the five options, you will see that this code requires more knowledge of Threads, Runnables and concurrency issues.  For those comfortable with Java thread and concurrency API, this may not be an issue.  Others may like a little simpler API.  For the latter, stay tuned to the other options.  However, the runOnUiThread() method call is actually a convenience method in that it hides many of the details associated with event queue messaging.

Finally, the runOnUiThread does come with one nice feature.  If the runOnUiThread method is called from code running on the UI thread, it executes immediately and does not post a message into the event message queue.  This convenience means you don’t have to check what thread you are running on when using this option.

WRAP UP

Stay tuned to this blog site for posts on the other four Android thread communication options.  If you need help on your mobile project (Android, iOS, other) let Intertech help.  We offer consultingand trainingservices to give your mobile team a leg up.

Read more: http://www.intertech.com/Blog/android-non-ui-to-ui-thread-communications-part-1-of-5/#ixzz3MytKKGrr 
Follow us: @IntertechInc on Twitter | Intertech on Facebook

Read more: http://www.intertech.com/Blog/android-non-ui-to-ui-thread-communications-part-1-of-5/#ixzz3MytCz0RD 
Follow us: @IntertechInc on Twitter | Intertech on Facebook

Android Non-UI to UI Thread Communications(Part 1 of 5)的更多相关文章

  1. Android Non-UI to UI Thread Communications(Part 3 of 5)

    Original:http://www.intertech.com/Blog/android-non-ui-to-ui-thread-communications-part-3-of-5/ Conti ...

  2. Android Non-UI to UI Thread Communications(Part 2 of 5)

    Original:http://www.intertech.com/Blog/android-non-ui-to-ui-thread-communications-part-2-of-5/ his i ...

  3. Android子线程更新UI成功

    android子线程更新UI成功 今天在写demo的时候,在子线程中更新UI,发现更新成功,记录一下. protected void onCreate(Bundle savedInstanceStat ...

  4. Android Phonebook编写联系人UI加载及联系人保存流程(一)

    2014-01-06 17:05:11 将百度空间里的东西移过来. 本文适合ROM定制做Phonebook的童鞋看,其他人飘过即可- Phonebook添加/编辑联系人UI加载及保存联系人流程,是一系 ...

  5. 50个Android开发人员必备UI效果源码[转载]

    50个Android开发人员必备UI效果源码[转载] http://blog.csdn.net/qq1059458376/article/details/8145497 Android 仿微信之主页面 ...

  6. 【Android】11.0 UI开发(二)——列表控件ListView的简单实现1

    ************************ 转载请注明出处:https://www.cnblogs.com/xiaofu007/p/10342462.html ***************** ...

  7. 重大发现: windows下C++ UI库 UI神器-SOUI(转载)

    转载:http://www.cnblogs.com/setoutsoft/p/4996870.html 在Windows平台上开发客户端产品是一个非常痛苦的过程,特别是还要用C++的时候.尽管很多语言 ...

  8. 转: windows下C++ UI库 UI神器-SOUI

    转:http://www.cnblogs.com/setoutsoft/p/4996870.html 前言 在Windows平台上开发客户端产品是一个非常痛苦的过程,特别是还要用C++的时候.尽管很多 ...

  9. 小波说雨燕 第三季 构建 swift UI 之 UI组件集-视图集(六)Picker View视图 学习笔记

    想对PickerView进行操作,只能在代码中操作. 下面 ,再添加三个label组件,然后将所有组件配置到代码中(看代码),然后要实现对PickerView的操作,就要实现它的DataSource协 ...

  10. 【译】UI设计基础(UI Design Basics)--导航(Navigation)(六)

    [译]UI设计基础(UI Design Basics)--导航(Navigation)(六)

随机推荐

  1. WebP 原理和 Android 支持现状介绍(转)

    本文为腾讯Bugly开发者社区 投稿,作者:soonlai,版权归原作者所有,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/582939577ef9c5b70855 ...

  2. onethink连接操作 sqlite 数据库

    直接上干货:一个简单的demo onthink本身已经有sqlite数据库的驱动 不需要在下载 common下面的config文件: 'SQLITE'=> array( 'DB_TYPE' =& ...

  3. JS设计模式初探

    目的:设计模式众多,尝试用博客记录下学到的不同设计模式的优劣,方便以后查阅. 前言:半年前看高程的时候看到设计模式这章,云里雾里,不是看不明白,而是不明白为啥要如此麻烦只为创建一个对象.直到最近完成了 ...

  4. Oracle数据库说明

  5. C++经典编程题#4:单词翻转

    总时间限制:  1000ms  内存限制:  65536kB 描述 输入一个句子(一行),将句子中的每一个单词翻转后输出. 输入 只有一行,为一个字符串,不超过500个字符.单词之间以空格隔开. 输出 ...

  6. android 23 启动带2个Categories值的预定义acticity和桌面activity

    mainActivity.java package com.sxt.day04_07_twoaction; import android.os.Bundle; import android.app.A ...

  7. Jquery函数实现时间显示模式为更新于+被当前时间减去后剩余的时间值(例如:更新于三小时前)的处理。

    var time_eles = $(".time_tranfer"); for(var i =0; i < time_eles.length;i++){ var time_e ...

  8. ie 如何判断正在执行的脚本

    1.在非ie浏览器里,script上的onload事件会准确地在脚本执行完以后触发   2.在ie浏览器里,如果脚本是在缓存里的话,那么onload事件是在你把script标签插入Dom结束时马上执行 ...

  9. cglib应用

    JDK的动态代理,经常被用来动态地创建对象的代理.JDK的动态代理用起来非常简单,但是有一个限制,就是使用动态代理的对象必须实现一个或多个接口.如果想代理没有实现接口,还可以使用cglib包来完成代理 ...

  10. VIM编辑器操作命令积累

    开始学习VIM编辑器了,计划着每周学习几个新命令,记录在本篇博客中. 1.第一次接触 vi demo.txt 进入Normal模式查看文本 i 进入Insert模式插入内容,编辑文本 nG n代表行号 ...