Android 在非UI线程直接更新UI信息

Android 说明文档明确指出不能在非UI线程直接更新UI线程的信息,否则系统会抛出类似如下异常:

09-15 21:37:09.335: E/AndroidRuntime(4507): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

文档建议使用Handler+Thread实现异步线程的UI更新,但是在日常工作中,突然发现在非UI线程居然可以直接更新UI信息,当时令我非常惊讶。

这是一个见证奇迹的旅程,请跟随我的思路,为你揭开Android非UI线程直接更新UI信息的神秘面纱!

以下是简单的代码验证(MainActivity.java):

package com.jony.update.ui;import android.os.Bundle;import android.app.Activity;import android.app.ProgressDialog;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.view.Menu;import android.widget.Button;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.TextView;public class MainActivity extends Activity {private TextView message;private ProgressDialog pd;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);message = (TextView) findViewById(R.id.message);pd = ProgressDialog.show(this, "Title", "Loading…");// Main thread IDSystem.out.println("Main Thread ID—>" + Thread.currentThread().getId());new Thread(){@Overridepublic void run() {// Sub thread IDSystem.out.println("Sub Thread ID—>" + Thread.currentThread().getId());LinearLayout layout = (LinearLayout) message.getParent();// Change the text viewmessage.setBackgroundColor(0Xffbbcc);message.setText(getResources().getString(R.string.update_content));message.setText("Hello jony");message.setTextSize(32);// Add text viewTextView add_view = new TextView(getApplicationContext());add_view.setText(getResources().getString(R.string.update_content));add_view.setTextSize(25);add_view.setText("Change content");// Add image viewImageView imageView = new ImageView(getApplicationContext());Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);imageView.setImageBitmap(bitmap);layout.addView(add_view);layout.addView(imageView);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}//Button button = new Button(getApplicationContext());//button.setText("commit");//layout.addView(button);pd.dismiss();}}.start();}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.activity_main, menu);return true;}}

以上代码片段开启了一个非UI线程,并在该线程中直接更新UI信息。经过运行测试,能够正常运行,证明了在非UI线程可以直接更新UI信息。My God,正不是和Google官方文档说的互相矛盾吗?猜想——难道这是Google大神的Bug?

当解除上述代码片段的注释部分:

Button button = new Button(getApplicationContext());button.setText("commit");layout.addView(button);

再次运行以上测试代码,系统会抛出如下异常:

09-15 22:17:34.371: E/WindowManager(6248): Activity com.jony.update.ui.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@414250a0 that was originally added here

简单说明一下以上异常,以上异常信息描述的大概是——MainActivity窗口已经泄露,证明MainActivity已经被finish()或者是被销毁了

既然找到问题所在了,那我们就要证明一下是不是在执行以下代码的时候,MainActivity已经被系统finish了?

layout.addView(button);

简单更改一下以上代码,更改后的代码如下所示(MainActivity):

package com.jony.update.ui;import android.os.Bundle;import android.app.Activity;import android.app.ProgressDialog;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.view.Menu;import android.widget.Button;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.TextView;public class MainActivity extends Activity {private TextView message;private ProgressDialog pd;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);message = (TextView) findViewById(R.id.message);pd = ProgressDialog.show(this, "Title", "Loading…");// Main thread IDSystem.out.println("Main Thread ID—>" + Thread.currentThread().getId());new Thread(){@Overridepublic void run() {// Sub thread IDSystem.out.println("Sub Thread ID—>" + Thread.currentThread().getId());LinearLayout layout = (LinearLayout) message.getParent();// Change the text viewmessage.setBackgroundColor(0Xffbbcc);message.setText(getResources().getString(R.string.update_content));message.setText("Hello jony");message.setTextSize(32);// Add text viewTextView add_view = new TextView(getApplicationContext());add_view.setText(getResources().getString(R.string.update_content));add_view.setTextSize(25);add_view.setText("Change content");// Add image viewImageView imageView = new ImageView(getApplicationContext());Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);imageView.setImageBitmap(bitmap);layout.addView(add_view);layout.addView(imageView);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}pd.dismiss();Button button = new Button(getApplicationContext());button.setText("commit");System.out.println("Tha MainActivity is finished?");layout.addView(button);System.out.println("Yes,It is.");}}.start();}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.activity_main, menu);return true;}@Overrideprotected void onPause() {// TODO Auto-generated method stubsuper.onPause();System.out.println("onPause");}@Overrideprotected void onStop() {// TODO Auto-generated method stubsuper.onStop();System.out.println("onStop");}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();System.out.println("onDestroy");}}分明是比谁记的都清楚,比谁都更加在意,

Android 在非UI线程直接更新UI信息

相关文章:

你感兴趣的文章:

标签云: