This is the last post in my series regarding Android thread communications.  Parts 1 through 4 are linked in below.

In this series, I have so far outlined four different approaches for how Android non-user interface threads can communicate user interface (UI) updates back to the UI thread.  As you have learned in this series, new threads to perform longer running work is the way to build applications and to avoid Android Not Responsive popups, but if those non-UI threads try to update UI components (like putting new String data in a TextView widget) they trigger a CalledFromWrongThreadException.  Previous posts have used the Activity’s runOnUiThread() method, a View’s post() method, the Handler Framework, and Broadcast/BroadcastReceiver components to handle non-UI to UI thread communications.  In this last post, my favorite option – the AsyncTask – is explored.

THE SIMPLE APP REVIEW

As reminder or note to those looking at these posts out of sequennce, throughout this series, I have used the same simple application (called Simple App) to demonstrate each communication option.  The Simple App has two buttons to start/stop a non-UI thread.  The non-UI thread’s job is to simulate long running work by generating a random number, then call the UI to have a TextView widget update the display of the random number, and then sleep for a number of seconds.

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

ASYNCTASK

The AsyncTask is a special Android convenience class for creating a new Thread that can “publish results on the UI thread without having to manipulate threads and/or handlers.”  That last quote is directly from the AsyncTask class documentationin the Android reference guide.  In other words, the AsyncTask was explicitly built to provide Android developers with an easy way to create threads that have a direct communication channel back to the UI thread.

In order to create an AsynTask, developers must extend the abstract AsyncTask super class and then implement the methods below.

  • doInBackground() – code here is executed on a new, non-UI thread that Android creates when the AsynTask is executed.  This is the only required method of an AsyncTask subclass.
  • onPreExecute() – code executed on the UI thread by Android before non-UI thread work is executed in doInBackground() code.
  • onPostExecute() – code executed on the UI thread by Android after non-UI thread work is executed in doInBackground.
  • onProgressUpdate – called on the UI thread by Android whenever publishProgress(Progress…) is called (typically in the doInBackground method) to provide the user interface (and user) with updates while the separate thread is still running.

Notice that three of four methods of the AsyncTask run on the UI thread.  The only method that runs in a non-UI thread is doInBackground().  So you can see the AsyncTask was really built to provide that non-UI to UI communications.

To exemplify AsyncTask’s capability, I created an inner class for the AsyncTask (called DoSomethingTask) to compute the random number and return the results to the UI.  Here is the code (again – it can be pulled from the Eclipse download referenced above).

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class DoSomethingTask extends AsyncTask<Void, String, Void> {
 
  private static final String TAG = "DoSomethingTask";
  private static final int DELAY = 5000; // 5 seconds
  private static final int RANDOM_MULTIPLIER = 10;
 
  @Override
  protected void onPreExecute() {
   Log.v(TAG, "starting the Random Number Task");
   super.onPreExecute();
  }
 
  @Override
  protected void onProgressUpdate(String... values) {
   Log.v(TAG, "reporting back from the Random Number Task");
   updateResults(values[0].toString());
   super.onProgressUpdate(values);
  }
 
  @Override
  protected void onCancelled(Void result) {
   Log.v(TAG, "cancelled the Random Number Task");
   super.onCancelled(result);
  }
 
  @Override
  protected Void doInBackground(Void... params) {
   Log.v(TAG, "doing work in Random Number Task");
   String text="";
   while (true) {
    if (isCancelled()) {
     break;
    }
    int randNum = (int) (Math.random() * RANDOM_MULTIPLIER);
    text = String.format(getString(R.string.service_msg), randNum);
    publishProgress(text);
    try {
     Thread.sleep(DELAY);
    } catch (InterruptedException e) {
     Log.v(TAG, "Interrupting the Random Number Task");
    }
   }
   return null;
  }
}

Note the random number generation (as well as the thread sleeping) occurs in the doInBackground() method – again to simulate long running, continuous work that is often accomplished in a background thread.  Also note that the doInBackground() method calls postProgress() with new String data after it has generated a random number and wants to send this data back to the UI thread.

DoSomethingTask extends AsyncTask and has three generic types.  The first, which in this example is Void, defines the input parameter type.  This simple task takes no input from the UI to generate a random number.  Your background work may need some information from the UI side to get it working and this parameter specifies the type of information being supplied.  This type defines the input parameter type for the doInBackground() method.

The second AsyncTask generic type provided, which is a String here, is the type of data passed to the onProgressUpdate() method in publishProgess() calls made from doInBackground().  Here, the new random number generated by doInBackground() is passed back to the UI thread in order to update the display by passing the random number as String text to the onProgressUpdate() call.

The last generic type to AsyncTask subclasses is the return type of the doInBackground() work.  In this case, the doInBackground() method does not return anything back to the UI thread (except through onProgressUpdate) so the third type is also Void.  Again, your non-UI threads may wish to return some information back to the thread’s creator and this is the type of information passed back.

With this AsyncTask in place, the UI – namely the owning Activity that drives the application – can create an instance of the AsyncTask (DoSomethingTask) and have its background work begin by calling execute.  This work is accomplished in the startGenerating() method (below) which I have setup to be called by an onClickListener waiting for the Start button to be pushed.

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

Finally, the AsyncTask calls the Activity’s updateResult() method (below) from the onProgressUpdate() method when a new random number is generated and the UI TextView displaying the number needs to be updated.  Again, this is possible because the onProgressUpdate() method runs on the UI thread.

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

Note additional cleanup methods are provided in the code to stop the AsyncTask when the Stop button is pushed. It should also be noted that this example was kept simple for demonstration sake.  Therefore, it has some faults you would want to correct in a real app situation.  For example, you might want to make sure only one AsyncTask is ever created (right now you could create many by clicking on Start many times).

CONSIDERATIONS OF OPTION 5 – ASYNCTASK

The AsyncTask is a real convenience for Android developers in that it allows them to accomplish multithreading without having to think about all the communications across threads and without having to think about Runnables, Thread instances, special methods to call, queues, etc. to get the work done.  The convenience of the three UI-thread methods makes getting information across the thread boundry real easy.  However, the AsyncTask is fairly basic and when more complex multithreading needs arise, it may be too simple to use.  In fact, the documentation is pretty clear about when to use AsyncTask and when to move to something like classes available in Java’s concurrent package.

AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and FutureTask.

While in this example, the AsyncTask was built as inner class to the Activity, the AsyncTask can be a completely separate class with no ties to the Activity or other UI component.  This allows the non-UI threads to be completely decoupled from the UI.

WRAP UP

So I hope on your next Android project, you’ll remember that you have lots of options for thread communications when it comes time to move background work to a separate non-UI thread.  Namely, you can:

  • Use runOnUiThread( ) method call
  • Use post( ) method call
  • Use the Handler framework
  • Use a Broadcasts and BroadcastReceiver (optionally with LocalBroadcastManager)
  • Use an AsyncTask’s onProgressUpdate( ) method

Good Android developers know it is important to use separate threads to avoid ANR.  The trick is sometimes figuring out how to get those threads communicating without creating other problems like CalledFromWrongThreadException.  Now you are armed with an understanding of thread communication options and considerations for making the best decision for your application needs.

Allow Intertechto help guide you through other mobile development technology issues and considerations.  If you need training in Android, iOS or other mobile development platform, please checkout our mobile program.  Or, contact our consulting departmentif you need some help on your mobile project.  We are the home of instructors that consult and consultants that teach.

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

android-non-ui-ui-thread-communications-part-5-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的四种方式 2015-09-06 09:23 segmentfault 字号:T | T 大家都知道由于性能要求,android要求只能在UI线程中更新UI,要想在其他线程中 ...

  4. Android开发之UI更新交互机制与实例解析

    android开发过程中,经常需要更新UI的状态和文案等.这是就需要对UI进行 更新.在android中更新UI一般有三种方法,handler机制.RunOnUiThread方法以及AsyncTask ...

  5. Android开发 ---基本UI组件7 :分页功能、适配器、滚动条监听事件

    效果图: 1.activity_main.xml 描述: 定义了一个按钮 <?xml version="1.0" encoding="utf-8"?> ...

  6. Android开发 ---基本UI组件4:拖动事件、评分进度条、圆圈式进度条、进度条控制

    Android开发 ---基本UI组件4 1.activity_main.xml 描述: 定义了一个按钮 <?xml version="1.0" encoding=" ...

  7. android线程控制UI更新(Handler 、post()、postDelayed()、postAtTime)

    依照以下的理解就是handler与ui线程有一定的关联能够由于更新界面仅仅能在主线程中全部更新界面的地方能够在接受消息的handleMessage那里还有更新界面能够在handler.port(new ...

  8. Android多线程更新UI的方式

    Android下,对于耗时的操作要放到子线程中,要不然会残生ANR,本次我们就来学习一下Android多线程更新UI的方式. 首先我们来认识一下anr: anr:application not rep ...

  9. ReactNative Android之原生UI组件动态addView不显示问题解决

    ReactNative Android之原生UI组件动态addView不显示问题解决 版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请表明出处:http://www.cnblogs.com ...

  10. Android开发 ---基本UI组件6 :只定义一个listView组件,然后通过BaseAdapter适配器根据数据的多少自行添加多个ListView显示数据

    效果图: 1.activity_main.xml 描述: 定义了一个按钮 <?xml version="1.0" encoding="utf-8"?> ...

随机推荐

  1. [转]"error while loading shared libraries: xxx.so.x" 错误的原因和解决办法

    [转]"error while loading shared libraries: xxx.so.x" 错误的原因和解决办法 http://blog.csdn.net/sahuso ...

  2. 实体框架 (EF) 入门 => 六、性能注意事项

    这个还真是复杂,看了看微软的文档,有些根本就看不懂,有些能看懂,但对我这种菜鸟也不会去用. 无从下手啊,前面放了几个链接,挨个试试吧. 一.显式打开连接 这个我测试过,有些时候,需要我们显示打开连接, ...

  3. Java Day 14

    多线程--线程间通信 对同一个资源进行处理,但是任务却不同 线程间通信--等待唤醒机制 1.wait();   线程处于冻结状态,被wait线程存储在线程池中 2.notify(); 从线程池唤醒一个 ...

  4. copy-mutableCopy

    copy和mutableCopy语法的目的:改变副本的时候,不会影响到源对象:调用Copy产生的对象是不可变的,调用mutableCopy产生的对象是可变的,与调用对象是否可变无关. Copy 需要先 ...

  5. Delphi 调试日子 - TLogger

    这段时间又开始用delphi了,才发现我对它这么的不熟悉! 简单的而有效的调试工具 Logger 这个是“榕树下”的作品,小巧而精悍.稍微调整了一下.在需要的地方加入 {$IFDEF DEBUG}   ...

  6. 团队项目--“我爱淘”校园二手书店 NABC分析

    本项目的特点之一:可查询功能 NABC分析: N(Need):方便校园里的学生查找自己需要的二手书籍,免了同学想买二手书还得跑到阿姨那里去看. A(Approach):将学生的信息和书籍的信息都存放在 ...

  7. C++四则运算出题器---有答案版

    一.实验题目 四则运算扩展----能接受答案并判断对错然后给出成绩. 二.实验思路 在每次输出算式后面输入答案,然后判断对错,对则统计. 稍微优化了一下界面. 三.代码 // 12345.cpp : ...

  8. 华为p7怎么打开usb调试模式

    在应用程序列表中选择[设置]进入系统设置菜单,点击[关于手机]  2.在"版本号"上面连续点击七次:  3.现在返回"设置"界面,发现多了一个"开 ...

  9. 【环境】VS2013和MATLAB相互调用混合编程

    Visual Studio和MATLAB混合编程,有两种方法: 1 MATLAB调用C程序: 2 VS调用MATLAB(目前见到的都是VS,其他编译器如codeblocks,或不提供这项功能): 前一 ...

  10. 老陈 WPF

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.W ...