• Android 通过广播来异步更新UI


    之前的项目里要做一个异步更新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(){
    
    		@Override
    		public void handleMessage(Message msg) {
    			// TODO Auto-generated method stub
    			super.handleMessage(msg);
    			if(msg.arg1 ==0){
    				hellworld.setText("更新UI - "+ i);
    				i++;
    			}
    		}
    		
    	};
    	public Handler mHandler =new Handler(){
    
    		@Override
    		public void handleMessage(Message msg) {
    			// TODO Auto-generated method stub
    			super.handleMessage(msg);
    			if (msg.arg1 == 1  ){
    				new Thread(new Runnable(){
    
    					@Override
    					public void run() {
    						// TODO Auto-generated method stub
    						System.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 block
    							e.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(){
    
    			@Override
    			public 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;
    		
    	}
    
    	@Override
    	public 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,非常奇怪~~~求大神解答


  • 相关阅读:
    SAP MM模块教程(1)— 概述
    CodeSmith Generator
    EasyUI 左侧 tree 右侧 DataGrid模板
    C# 数据库访问公共类
    Easyui datagrid toolbar 模板
    EasyUI combogrid 更新查询参数 queryParams 重新加载
    Jenkins的搭建与使用
    Idea2020激活,全网最新教程(各版本通用),亲测2089!!!
    阿里云盘开启“个人云种子用户报名
    尚硅谷Java互联网大厂面试题第三季,1024干货
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4296424.html
Copyright © 2020-2023  润新知