Android--Handler

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android--Handler相关的知识,希望对你有一定的参考价值。

一、Handler的定义:

主要接受子线程发送的数据, 并用此数据配合主线程更新UI。

解释:当应用程序启动时,android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件, 进行事件分发, 比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。  如果此时需要一个耗时的操作,例如: 联网读取数据,    或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示  "强制关闭"。  这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,,Android主线程是线程不安全的, 也就是说,更新UI只能在主线程中更新,子线程中操作是危险的。 这个时候,Handler就出现了。,来解决这个复杂的问题 ,由于Handler运行在主线程中(UI线程中),  它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据)  , 把这些消息放入主线程队列中,配合主线程进行更新UI。

二、Handler一些特点

handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用:

(1)安排消息或Runnable 在某个主线程中某个地方执行;

(2)安排一个动作在不同的线程中执行。

Handler中分发消息的一些方法

post(Runnable)

postAtTime(Runnable,long)

postDelayed(Runnable long)

sendEmptyMessage(int)

sendMessage(Message)

sendMessageAtTime(Message,long)

sendMessageDelayed(Message,long)

以上post类方法允许你排列一个Runnable对象到主线程队列中,

sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新。

技术分享

三、Handler实例

listview显示数据,布局和上一篇一样,MainActivity类代码

package com.example.multithreadind01;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;


public class MainActivity extends Activity {

    private String fromDb_str1 = "";
    private Button btn;
    private TextView tv;
    private ListView lv;
    private BaseAdapter adapter;
    private List<User> userList = new ArrayList<User>();
    private Runnable doInBackground1;
    private Runnable doInBackground2;
    
    //1.跟着主线程走,可以碰UI
    //2.能够接受子线程发送的消息(Message)
    //        子线程类本身不可以发信息
    private Handler handler;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        Log.i("UI_MainThread","id:"+Thread.currentThread().getId());
        
        for (int i = 0; i < 5; i++) {
            User u = new User();
            u.setUsername("小明"+i);
            u.setSex("女"+i);
            userList.add(u);
        }
        
        tv =(TextView)findViewById(R.id.textView1);
        btn =(Button)findViewById(R.id.button1);
        btn.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                //1.访问数据库或者互联网(但会卡的)
                //2.更新界面
                Thread t1 = new Thread(doInBackground1);
                t1.start();
                
                Thread t2 = new Thread(doInBackground2);
                t2.start();
                
            }
        });
        adapter = new BaseAdapter(){

            @Override
            public int getCount() {
                // TODO Auto-generated method stub
                return userList.size();
            }

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                LayoutInflater inflater = MainActivity.this.getLayoutInflater();
                View view;
                if (convertView==null){
                    view = inflater.inflate(R.layout.item, null);
                }
                else{
                    view = convertView;
                }
                
                TextView tv_username = (TextView)view.findViewById(R.id.username);
                TextView tv_sex = (TextView)view.findViewById(R.id.sex);
                tv_username.setText(userList.get(position).getUsername());
                tv_sex.setText(userList.get(position).getSex());
                return view;
            }
            
            @Override
            public Object getItem(int position) {
                // TODO Auto-generated method stub
                return null;
            }

            @Override
            public long getItemId(int position) {
                // TODO Auto-generated method stub
                return 0;
            }
        };
        lv = (ListView)findViewById(R.id.listView1);
        lv.setAdapter(adapter);
        
        handler = new Handler(){
            
            //1.消息msg来自于子线程
            //2.消息可以多个,采用msg.what识别
            //3.处理消息,一般就会更新UI
            //4.此方法可以参考onPostExecute
            @Override
            public void handleMessage(Message msg) {
                
                super.handleMessage(msg);
                int msgwhat = msg.what;
                Log.i("handler","已经收到消息,消息what:"+msgwhat+",id:"+Thread.currentThread().getId());
                
                if (msgwhat==1){
                    //更新helloworld
                    tv.setText("子线程让我更新"+msgwhat);
                }
                if (msgwhat==2){
                    //更新ListView
                    adapter.notifyDataSetChanged();
                }

            }
            
        };
        
        //子线程代码1
        doInBackground1 = new Runnable() {
            
            @Override
            public void run() {
                Log.i("sub_Thread","子线程1启动,id:"+Thread.currentThread().getId());
                
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
                //1.访问数据库或者互联网,不在UI进程,所以不卡
                Message msg = new Message();
                //对消息一个识别号,便于handler能够识别
                msg.what = 1;
                handler.sendMessage(msg);
                Log.i("sub_Thread","子线程1已经发送消息给handler");
            }
        };
        
        
        
        //子线程代码1
        doInBackground2 = new Runnable() {
            
            @Override
            public void run() {
                Log.i("sub_Thread","子线程2启动,id:"+Thread.currentThread().getId());
                
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }               
                Message msg = new Message();
                //对消息一个识别号,便于handler能够识别
                msg.what = 2;
                //handler.sendMessage(msg);
                handler.sendMessageDelayed(msg, 500);                
                //访问互联网,下载最新的,更新data,但不碰界面
                for (User user : userList) {
                    user.setSex("女");
                }
                
                Log.i("sub_Thread","子线程2已经发送消息给handler");
            }
        };
        
    }
}

效果图:

      技术分享       技术分享

    技术分享     技术分享

四、总结:

1)android系统是单线程系统,为了实现多线程的效果,采用了message queue。

2)为实现多线程,可采用runOnUiThread,post,handle,AsyncTask技术实现。

 

以上是关于Android--Handler的主要内容,如果未能解决你的问题,请参考以下文章

Android Handler 具体解释

Android Handler内存泄露

Android handler 报错处理Can't create handler inside thread that has not called Looper.prepare()(示例代码

Android高手进阶教程之----Android Handler的使用!!!

Android Handler 内存泄漏问题

从Android Handler内部类到WeakReference的知识关联