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

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.

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.”

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.

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.

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

时间: 2024-09-28 03:01:32

Android Non-UI to UI Thread Communications(Part 1 of 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/ Continuing my series on Android non-UI thread-to-UI thread communications, this post covers use of the Handler Framework to facilitate the communications. 

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 is the second part of my series of blog posts on Android non-UI thread-to-UI thread communications. See herefor the start of the series.  As a refreshe

Android UI编程(4)——Thread、Message、Handler

当应用程序启动时,会开启一个主线程(也就是UI线程),由它来管理UI,监听用户点击,来响应用户并分发事件等.所有一般在主线程中不要执行比较耗时的操作,如延时.下载网络数据.死循环,否则出现ANR错误.所以就将这些操作放在子线程中,但是由于Android UI线程是不安全的,所有只能在主线程中更新UI.使用Thread来创建子线程.使用Message来存储数据.使用Handler来处理消息数据. 总结: 1.子线程与UI主线程之间通过Message来传递数据,需要创建一个新类(MyHandler)

Android子线程更新UI主线程方法之Handler

背景: 我们开发应用程序的时候,处于线程安全的原因子线程通常是不能直接更新主线程(UI线程)中的UI元素的,那么在Android开发中有几种方法解决这个问题,其中方法之一就是利用Handler处理的. 下面说下有关Handler相关的知识. 多线程一些基础知识回顾:在介绍Handler类相关知识之前,我们先看看在Java中是如何创建多线程的方法有两种:通过继承Thread类,重写Run方法来实现通过继承接口Runnable实现多线程 具体两者的区别与实现,看看这篇文章中的介绍:http://de

Android关于线程更新UI的方法

Android关于线程更新UI的方法 在一个Android 程序开始运行的时候,会单独启动一个Process.默认的情况下,所有这个程序中的Activity或者Service(Service和 Activity只是Android提供的Components中的两种,除此之外还有Content Provider和Broadcast Receiver)都会跑在这个Process.   一个Android 程序默认情况下也只有一个Process,但一个Process下却可以有许多个Thread.   在

Android中子线程和UI线程之间通信的方式

Android中子线程和UI线程之间通信的详细解释 1.在多线程编程这块,我们经常要使用Handler,Thread和Runnable这三个类,那么他们之间的关系你是否弄清楚了呢?下面详解一下. 2.首先在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行. 3.Handler: (1).概念: Handler是沟通Activity 与Thread/runnable的桥梁.而Handler是运行在主UI线程中的,它与子线程

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

50个Android开发人员必备UI效果源码[转载] http://blog.csdn.net/qq1059458376/article/details/8145497 Android 仿微信之主页面实现篇Android 仿微信之界面导航篇Android 高仿QQ 好友分组列表Android 高仿QQ 界面滑动效果Android 高仿QQ 登陆界面Android 对Path的旋转效果的拓展Android高仿360安全卫士布局源码Android SlidingDrawer 滑动抽屉效果Androi

Android基础知识(1)——UI编程

我学习android一段时间了,看着大牛们的各种神博客,心里也痒痒的,希望有一天也能成为他们一样. 我知道,这些都是一滴一滴的积累,所有我也需要找到我的学习方法,打好基础,做出属于我自己的成果. 当然,作为一名菜鸟程序员,更加要懂得把知识整理归类,方便记忆. ----------------------------------------------------------- 在学校里听老师讲课,总会让学生误会程序员的主要工作不是界面美化,那都是美工做得事情.但随着移动开发的不断发展,在软件开发

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

转:http://www.cnblogs.com/setoutsoft/p/4996870.html 前言 在Windows平台上开发客户端产品是一个非常痛苦的过程,特别是还要用C++的时候.尽管很多语言很多方法都可以开发Windows桌面程序,目前国内流行的客户端产品都是C++开发的,比如QQ,YY语音,迅雷等.快速,稳定是我认为的应用软件开发框架最基本的要求,对于UI还有两个要求就是界面美观,配置灵活.C++语言满足了快速的要求,传统的客户端软件开发框架如MFC,WTL等满足了稳定的要求.然

学习IOS开发UI篇--UI知识点总结(四) UITabelView/UITableViewCell

UITabelView:常用属性 @property (nonatomic)          CGFloat    rowHeight;             // will return the default value if unset @property (nonatomic)          CGFloat     sectionHeaderHeight;   // will return the default value if unset @property (nonatom