Android学习笔记:关于Handler的详解(一)

Handler在android的学习当中应用是非常多的,我们就依次的来解决handler相关问题。其实在handler当中有很多问题比较难理解,比如我们在子线程中通过post的方法发送一条消息,然后就立即能够在handlemessage方法中接受到这条消息,在最初我们学习中都会比较困惑,那么今天我们通过handler的详细讲解,让大家了解handler的机制是什么,并且结合源码和大量的实例让大家更深的了解handler,通过今天的学习,相信大家对handler会有一定的掌握,handler对我们日后android的开发或者面试中都是非常重要的存在。
1. Handler是什么?

在我们学习一门技术和语言之前,一定要先了解以下这门技术和语言是什么,不要盲目的去学习,因为技术太多了,我们要把经历放在核心的技术当中。
Handler在我们android开发当中是一个非常重要的机制,那handler又是什么呢?handler是android提供用于更新ui的一套机制,也是消息处理的机制。

handler的主要作用有两个:
(1):在新启动的线程中发送信息。
(2):在主线程中获取,处理信息。

2. 为什么要是用handler?

如果我们不用handler去发送消息,更新ui可以么?

是不行的。 Android在设计的时候,就封装了一套消息创建,传递,处理机制,如果不遵循这样的机制,就没有办法更新ui信息的,就会抛出异常信息。
异常的描述:不能在非ui线程中去更新ui。
Only the original thread that created a view hierarchy can touch its views.

3.Handler怎么用呢?

想要了解handler怎么用,就需要去看一下api文档。

一个handler允许你发送和处理message和Runnable对象在相关联的MessageQueen。每个handler实例都与一个单独的线程绑定,该线程带有消息队列MessageQueen。当你创建一个新的handler时,它默认会绑定到创建线程的MessageQueen中,从这一点上,它将传递消息和runnable对象,在MessageQueen中执行这个消息。
Handler有两个主要用途:

1.合理调度安排消息和runnable对象,使它们在将来的某个点被执行。
2.将一个动作入队安排在非当前线程执行。

调度消息是通过一系列的post方法和sendMessage方法。
post方法允许你向消息队列中入队一些Runnable对象,在它们被接收到的时候会被调用.
sendMessage方法允许你入队一个消息对象(Message),包含一个bundle数据,之后将会被Handler的handleMessage(Message)方法所处理。
当为应用程序创建一个进程时,它的主线程专门负责运行一个消息队列,它负责管理顶级应用程序对象(活动、广播接收器等),以及它们所创建的任何窗口。您可以创建自己的线程,并通过一个处理程序与主应用程序线程进行通信。这是通过之前调用的post或SendMessage方法从新的线程。给定的runnable对象或消息将被安排在处理程序的消息队列,在适当时候进行处理。

实例一:handler的post基本用法

public class MainActivity extends Activity {
    private TextView tv;
    private Handler handler = new Handler();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView)findViewById(R.id.tv);
        new Thread(){
            public void run() {
                try {
                    Thread.sleep(2000);
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            tv.setText("123456789");
                        }
                    });

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

实例二:仿照淘宝页面切换图片
布局代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/img"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:src="@drawable/d_xiongmao" />
</RelativeLayout>

java逻辑代码:

package com.qf.handler_demo02;

import javax.crypto.spec.IvParameterSpec;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.view.Menu;
import android.widget.ImageView;

public class MainActivity extends Activity {
    private ImageView img;
    private int images[] = {R.drawable.d_xiongmao,R.drawable.d_xixi,R.drawable.d_xu,R.drawable.d_yinxian};
    private int index = 0;
    private Handler handler = new Handler();
    private MyRunnable runnable = new MyRunnable();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        img = (ImageView)findViewById(R.id.img);
        //每隔一秒,发送一条runnable对象。
        handler.postDelayed(runnable, 1000);
    }
    class MyRunnable implements Runnable{
        @Override
        public void run() {
            index++;
            index=index%4;
            img.setImageResource(images[index]);
            handler.postDelayed(runnable, 1000);
        }
    }
}

实例三:显示倒计时效果
布局代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center" >
    <TextView
        android:id="@+id/tv_time"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:textSize="60sp"
        android:text="60"
        android:gravity="center"/>
    <ImageView 
        android:id="@+id/iv_time"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:src="@drawable/d_doge"
        android:visibility="gone"/>
    <Button
        android:id="@+id/stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="stop"
        android:text="停止倒计时" />
</LinearLayout>

java逻辑代码:

public class MainActivity extends Activity {
    private ImageView iv;
    private TextView tv;
    private int times = 60;     //定义一个最初的时间
    private Handler handler = new Handler();
    private MyRunnable runnable = new MyRunnable();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView)findViewById(R.id.tv_time);
        iv = (ImageView)findViewById(R.id.iv_time);
        handler.postDelayed(runnable, 1000);        
        //一秒之后发送一条消息。
    }
    class MyRunnable implements Runnable{
        @Override
        public void run() {
            times--;    //每运行一次,当前的时间数就减去一;
            tv.setText(times+"");   //把时间设置在当前的textview中
            if (times == 0){ //当时间等于0时,停止发送信息。
                tv.setVisibility(View.GONE);
                iv.setVisibility(View.VISIBLE);

            }else {                 //否则继续发送信息
                handler.postDelayed(runnable, 1000);
            }
        }
    }
    //移除正在调用的runnable对象
    public void stop(View view){
        handler.removeCallbacks(runnable);
    }
}

以上三个例子是关于handler的post发送runnable对象的应用。
下面我们看一下关于handler是如何通过sendMessage发送信息。
首先给大家介绍一下Message的概念:

Message是线程之间传递信息的载体,包含了对消息的描述和任意的数据对象。
Message中包含了两个额外的 int字段和一个object字段,这样在大部分情况下,使用者就不需要再做内存分配工作了。
虽然Message的构造函数是public的,但是最好是使用Message.obtain( )或Handler.obtainMessage( )函数来获取Message对象,因为Message的实现中包含了回收再利用的机制,可以提供效率。

实例四:介绍message的arg1,arg2,obj字段
布局代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
</RelativeLayout>

逻辑代码:

public class Person {
    String name;
    int age;
    String sex;
    public Person() {
    }
    public Person(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
    }
}

activity中的代码:

public class MainActivity extends Activity {
    private TextView tv;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //能获取到msg.arg1和arg2的值。
            tv.setText("msg.arg1:"+msg.arg1+"----msg.arg2="+msg.arg2);
            //能够获取得到msg.obj当中的内容
            tv.setText(msg.obj+"");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView)findViewById(R.id.tv);
        new Thread(){
            public void run() {
                try {
                    Thread.sleep(2000);
                    //获得Message对象的三种方法
                    //1.new Message():使用构造方法
//                  Message msg = new Message();
                    //2.obtain方法,回收再利用的机制
//                  Message msg = Message.obtain();
                    //3.调用handler的obtainMessage方法,实质和obtain一样
                    Message msg = handler.obtainMessage();
                    msg.arg1 = 98;
                    msg.arg2 = 35;
                    Person person = new Person("jerry", 12, "男");
                    msg.obj = person;
                    handler.sendMessage(msg);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

以上代码能够看出由handler发送的信息,然后也由他自己来接受信息。这个就是handler对于消息处理的机制。同时当我们通过message.sendToTarget()的方法,也可以将信息发送给指定的handler对象。通过查看源码发现,还是调用了handler的sendMessage的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值