android-non-ui-ui-thread-communications-part-5-5
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的更多相关文章
- 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 ...
- 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 ...
- Android异步更新UI的四种方式
Android异步更新UI的四种方式 2015-09-06 09:23 segmentfault 字号:T | T 大家都知道由于性能要求,android要求只能在UI线程中更新UI,要想在其他线程中 ...
- Android开发之UI更新交互机制与实例解析
android开发过程中,经常需要更新UI的状态和文案等.这是就需要对UI进行 更新.在android中更新UI一般有三种方法,handler机制.RunOnUiThread方法以及AsyncTask ...
- Android开发 ---基本UI组件7 :分页功能、适配器、滚动条监听事件
效果图: 1.activity_main.xml 描述: 定义了一个按钮 <?xml version="1.0" encoding="utf-8"?> ...
- Android开发 ---基本UI组件4:拖动事件、评分进度条、圆圈式进度条、进度条控制
Android开发 ---基本UI组件4 1.activity_main.xml 描述: 定义了一个按钮 <?xml version="1.0" encoding=" ...
- android线程控制UI更新(Handler 、post()、postDelayed()、postAtTime)
依照以下的理解就是handler与ui线程有一定的关联能够由于更新界面仅仅能在主线程中全部更新界面的地方能够在接受消息的handleMessage那里还有更新界面能够在handler.port(new ...
- Android多线程更新UI的方式
Android下,对于耗时的操作要放到子线程中,要不然会残生ANR,本次我们就来学习一下Android多线程更新UI的方式. 首先我们来认识一下anr: anr:application not rep ...
- ReactNative Android之原生UI组件动态addView不显示问题解决
ReactNative Android之原生UI组件动态addView不显示问题解决 版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请表明出处:http://www.cnblogs.com ...
- Android开发 ---基本UI组件6 :只定义一个listView组件,然后通过BaseAdapter适配器根据数据的多少自行添加多个ListView显示数据
效果图: 1.activity_main.xml 描述: 定义了一个按钮 <?xml version="1.0" encoding="utf-8"?> ...
随机推荐
- java 版本安装
系统:Ubuntu 10.04 JDK:jdk-6u20-linux-i586.bin 当然,我已经在sun的官方网站上下载好了必要的jdk,由于是在linux下安装,跟平时习惯的windows有所不 ...
- 60.ISE PhysDesignRules ERROR
PhysDesignRules:2100 - Issue with pin connections and/or configuration on block:<U_ila_pro_0/U0/I ...
- C++ this指针详解
C++this指针操作 在这里总结一下this 指针的相关知识点. 首先,我们都知道类的成员函数可以访问类的数据(限定符只是限定于类外的一些操作,类内的一切对于成员函数来说都是透明的),那么成员 ...
- 安装Windows7出现:”安装程序无法创建新的系统分区 也无法定位系统分区“ 终极解决方案
参考:地址 解决方法: 1.先格式化一下你要装的那个盘,然后,拔出U盘,啥也别动,只拔出U盘就行,再装上U盘,然后刷新一下[选硬盘那里的高级选项中有格式化和刷新],再选择要安装的硬盘点下一步,OK了, ...
- From 《Soft Skill》——Chapter 69. My personal success book list
There have been many excellent books that have greatly influenced what I believe and how I behave. I ...
- hdu 1548 A strange lift 宽搜bfs+优先队列
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1548 There is a strange lift.The lift can stop can at ...
- 【BZOJ】【1269】【AHOI2006】文本编辑器editor
Splay Splay序列维护的模板题了……为了便于处理边界情况,我们可以先插入两个空格当作最左端和最右端,然后……其实本题主要考察的就是Build.splay和Findkth这三个操作,我们可以实现 ...
- javascript中继承(一)-----原型链继承的个人理解
[寒暄]好久没有更新博客了,说来话长,因为我下定决心要从一个后台程序员转为Front End,其间走过了一段漫长而艰辛的时光,今天跟大家分享下自己对javascript中原型链继承的理解. 总的说来, ...
- .net程序集强名称签名实践
引用: http://www.cnblogs.com/cpcpc/archive/2011/01/17/2123086.html 强名称是由程序集的标识加上公钥和数字签名组成的.其中,程序集的标识包 ...
- JavaScript垃圾回收
JavaScript内存监测工具 http://www.cnblogs.com/strick/p/4002010.html