Android在子线程中更新UI
我们在开发应用程序的时候,考虑到线程安全的问题,子线程是不能直接修改UI的,也就是说Android的UI也是不安全的线程,如果想要更新UI元素,则必须在主线程里执行,否则就会出现异常。
首次来看一个在子线程修改UI的例子:
1、新建一个TestDemo项目,然后修改MainActivity.xml中的代码,代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/btn_click_me" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="click me" /> <TextView android:id="@+id/tv_show_info" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="dd" /> </LinearLayout>
在布局文件MainActivity中添加了两个控件,一个Button和一个TextView.我希望当我点击Button时能够把TextView的Text属性值修改成我所希望的值。
下面来看一下MainActivity中的代码:
public class MainActivity extends ActionBarActivity implements OnClickListener { private static final String TAG = "MainActivity"; private Button btn_click_me; private TextView tv_show_info; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_click_me = (Button) findViewById(R.id.btn_click_me); tv_show_info = (TextView) findViewById(R.id.tv_show_info); btn_click_me.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_click_me: { log("----------------click------------------------"); new Thread(new Runnable() { @Override public void run() { tv_show_info.setText("hello world"); } }).start(); } break; default: break; } } public void log(String info) { Log.d(TAG, info); } }
这段代码很简单,在btn_click_me按钮的点击事件里面开启了一个子线程,然后在子线程中调用TextView的setText的方法将显示的字符串改成hello world。代码逻辑非常简单,不过这是在子线程中更新UI的。现在运行一下这段代码,你会发现程序崩溃了。查看LogCat中的错误日志,你可以看到造成崩溃的原因是由于在子线程中更新UI所导致的。异常信息如下:

以上可以证实了Android确实是不允许在子线程中对UI元素进行修改。但是Android为我们提供了一套异步消息处理机制,能够完美的解决在子线程中操作UI.现在我们来修改一下MainActivity中的代码。代码如下:
public class MainActivity extends ActionBarActivity implements OnClickListener { private static final String TAG = "MainActivity"; private Button btn_click_me; private TextView tv_show_info; private static final int UPDATA_TEXT=1; private Handler handler=new Handler(){ public void handleMessage(Message msg) { switch (msg.what) { case UPDATA_TEXT: tv_show_info.setText(msg.obj.toString()); break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_click_me = (Button) findViewById(R.id.btn_click_me); tv_show_info = (TextView) findViewById(R.id.tv_show_info); btn_click_me.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_click_me: { log("----------------click------------------------"); Message msg=new Message(); msg.what=UPDATA_TEXT; msg.obj="hello world"; handler.sendMessage(msg); } break; default: break; } } public void log(String info) { Log.d(TAG, info); } }
在修改后的代码里面新增了一个静态常量UPDATA_TEXT,用来表示更新textView的动作,然后又定义了一个Handler对象,并重写了父类的handlerMessage方法,在重写的方法中进行了对textView的操作。在重写的handlerMessage里面你会发现当msg.what的值等于UPDATA_TEXT时,就会将TextView的值改我msg.obj传递过去的值hello world.
浙公网安备 33010602011771号