Android 通过广播来异步更新UI

来源:互联网 发布:js 复选框控制display 编辑:程序博客网 时间:2024/05/22 08:08

之前的项目里要做一个异步更新UI的功能,但是结果出现了ANR,所以想写个demo来测试到底是哪个地方出现了问题,结果发现原来的思路是没有问题,郁闷~~

现在这个demo 就是模拟项目里面 的步骤

1、接收到系统的广播(现在模拟为人工发送)

2、广播接收到后,handler通知异步线程从网上下载数据,是异步(模拟为sleep)

3、数据下载完后handler再通知UI更新


下面是主要的两个代码,能够正确运行


package com.example.testanr;import android.support.v7.app.ActionBarActivity;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends ActionBarActivity {public TextView hellworld = null;public Button sendBroadcast = null;public final static String MY_ACTION = "com.example.testanr.MY_ACTION";public static int i = 0;public Handler updateUI  =new Handler(){@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);if(msg.arg1 ==0){hellworld.setText("更新UI - "+ i);i++;}}};public Handler mHandler =new Handler(){@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);if (msg.arg1 == 1  ){new Thread(new Runnable(){@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("Thread id is "+Thread.currentThread().getId()+",and Thread name is "+Thread.currentThread().getName());try {Thread.currentThread().sleep(15000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}Message msg =new Message();msg.arg1 =0;updateUI.sendMessage(msg);}}).start();}}};    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                hellworld = (TextView)findViewById(R.id.hello_world);        sendBroadcast = (Button)findViewById(R.id.sendBroadcast);        //生成一个BroadcastReceiver对象        TestReceiver  testReceiver = new TestReceiver(mHandler);//生成一个IntentFilter对象IntentFilter filter = new IntentFilter(); filter.addAction(MainActivity.MY_ACTION);//将BroadcastReceiver对象注册到系统当中MainActivity.this.registerReceiver(testReceiver, filter); System.out.println("Thread id is "+Thread.currentThread().getId()+",and Thread name is "+Thread.currentThread().getName());        sendBroadcast.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {// TODO Auto-generated method stub//发送广播Intent intent = new Intent();  intent.setAction(MainActivity.MY_ACTION);                  sendBroadcast(intent);  }                });    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        // Handle action bar item clicks here. The action bar will        // automatically handle clicks on the Home/Up button, so long        // as you specify a parent activity in AndroidManifest.xml.        int id = item.getItemId();        if (id == R.id.action_settings) {            return true;        }        return super.onOptionsItemSelected(item);    }}


还有reciever

package com.example.testanr;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.os.Handler;import android.os.Message;public class TestReceiver extends BroadcastReceiver {public Handler handler;public Message message = null;public TestReceiver(Handler handler){this.handler = handler;}@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stub//这里每次都要new,否者会报错message = new Message();message.arg1 = 1;handler.sendMessage(message);}}

现在才发现一个message是不能往MessageQueue里面发送多次的,否则会报这样的错

java.lang.IllegalStateException: The specified message queue synchronization  barrier token has not been posted or has already been removed.

就说这个message的synchronization  barrier token 已经发送过了的

但是项目里面的问题还没有解决,回头找出原因再发上来


我们知道ANR一般有三种类型

1KeyDispatchTimeout(5 seconds) --主要类型

按键或触摸事件在特定时间内无响应

2BroadcastTimeout(10 seconds)

BroadcastReceiver在特定时间内无法处理完成

3ServiceTimeout(20 seconds) --小概率类型

Service在特定的时间内无法处理完成

所以原因还是应该是第二种,可能没有模拟对


ANR的分析

如何调查并解决ANR

1:首先分析log

2: trace.txt文件查看调用stack.

3: 看代码

4:仔细查看ANR的成因(iowait?block?memoryleak?


但是项目里面log没有输出,是最奇怪的~~~

//************************************9-29更新****************8


回去一看果然是一个message往looper的messagequeue发送了多次!!!但是log没有输出exception,而且为什么会导致ANR,很奇怪~~~求大神解答


1 0