异常信息:android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Android 不允许在子线程中更新 UI。但是有时候又必须在子线程中进行操作,再对 UI 进行相应操作。
比如今天学习使用百度地图,主线程中初始化一个 textView 用于显示经纬度:
positionText = (TextView) findViewById(R.id.position_text_view);
在主线程中设置一个监听:
mLocationClient.registerLocationListener(new MyLocationListenr());
当应用程序有相关权限时,执行监听并对 textView 内容进行修改
@Override
public void onReceiveLocation(BDLocation bdLocation) {
final StringBuilder currentPosition = new StringBuilder();
currentPosition.append("经度:").append(bdLocation.getLatitude()).append("/n");
currentPosition.append("纬度:").append(bdLocation.getLongitude()).append("/n");
currentPosition.append("定位方式:");
if (bdLocation.getLocType() == BDLocation.TypeGpsLocation) {
currentPosition.append("GPS");
} else if (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation) {
currentPosition.append("network");
positionText.setText(currentPosition);
此时报错:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
只有原先穿件这个 View 的线程,才能对这个 View 进行操作。在主线程中创建的 View,所以对其操作必须在主线程中进行,即在主线程中:
positionText.setText(currentPosition);
目前我知道两种解决方案:
方案一:使用 runOnUiThread() 方法
runOnUiThread(new Runnable() {
@Override
public void run() {
positionText.setText(currentPosition);
}
});
方案二:使用 Handler
首先在监听器中创建一条 Message:
Message message = new Message();
message.what = UPDATE_TEXT;
Bundle bundle = new Bundle();
bundle.putString("currentPosition",currentPosition.toString());
message.setData(bundle);
handler.sendMessage(message);
因为还需要传一条信息给 TextView,所以用 Bundle 放数据。
再使用 Handler 接收 message 并对 UI 进行操作
private Handler handler = new Handler(){
public void handleMessage(final Message msg){
super.handleMessage(msg);
switch (msg.what){
case UPDATE_TEXT:
Bundle bundle = msg.getData();
String currentPosition = bundle.getString("currentPosition");
positionText.setText(currentPosition);
break;
default:
}
}
};