Android开发基础之Handler的使用

★Handler的使用


不如我们先了解下什么是Handler机制,他的作用是什么吧!

Handler的作用:

关于Handler我刚开始学习Android开发的时候我也是没有搞懂,我是在第二次重新学习的时候,也找了很多资料才明白的,从英语单词上来解释是“处理者”的意思,我从百度上搜到一个解释还比较详细,他是这样解释的:

当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件, 进行事件分发, 比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。  如果此时需要一个耗时的操作,例如: 联网读取数据,    或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示。

我个人的理解:

我觉得这些解释让我有时候也不是很懂,我从小语文就差,后来根据了解到,我的个人理解是,有时候我们会把一些组件的点击动作都写进主线程里面,有些动作需要延迟,比如progressbar进度条有些时候是延续性动作,但是如果都加入到主线程,那么这个动作就会占用主线程,然后如果占用达到一定程度,就会导致程序发生错误或假死的状态。还有比如点击一个Button更新TextView显示文字,一般新手就会用主线程去更新UI,但是现在就有一个Handler机制用子线程去更新UI的操作,专门针对一些耗时的操作,如果没有这个机制,你多个线程操作就会造成堵塞,超过5秒就会出现程序崩溃,假死的现象,有了Handler机制还能控制多个子线程同时进行,所以大家应该了解到了Handler的作用和必要性了吧!


在这里我会用一个app来演示Handler的简单使用方法

                                                             

在上面我们可以看见一共有4个Button按钮,每个按钮都会跳转到一个新的Activity演示一种Handler的使用,下面是我的代码。

案例一:

                                                    

点击start按钮以后TextView控件上一直反复打印更新中......直到点击end按钮停止

首先我们来看看戴安是怎么实现这个功能的

主要的关键代码是:

Handler handler = new Handler();
    Runnable update = new Runnable() {
        @Override
        public void run() {
            textview.append("\n更新中......");
            handler.postDelayed(update,1000);
        }
    };
这里是创建一个handler对象,新建一个子线程,里面调用textview.append()方法,打印一串字符串,然后再调用handler.postDelayed()方法,达到延迟效果

然后是两个按钮的监听器立的方法

 button_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.post(update);
            }
        });
        button_end.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.removeCallbacks(update);
            }
        });

handler.post()方法是开始执行,handler.removeCallbacks()方法是停止里面的对象update就是子线程的对象


案例二:

                                                     

点击start按钮显示一个进度条自动加载直到加载完成

我们来看一下关键的java代码:

 Handler handler = new Handler(){
        public void handleMessage(Message msg) {
            progressbar.setProgress(msg.arg1);
            handler.post(update);
        }
    };
    Runnable update = new Runnable() {
        int i = 0;
        @Override
        public void run() {
            i += 10;
            Message msg = handler.obtainMessage();
            msg.arg1 = i;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            handler.sendMessage(msg);
            if(i == progressbar.getMax())
                handler.removeCallbacks(update);
        }
    };

在这里比案例二的java代码中多了handlerMessage这个对象,这个对象主要作用就是传值的作用或者说是在子线程run()方法和Handler之间传递消息,让Handler判断什么时候开始执行子线程活该执行哪一个线程

Message msg = handler.obtainMessage();
            msg.arg1 = i;

这里的msg.arg就是一个惨就是用这个参数来决定进度条的每次增加多少

handler.sendMessage(msg);

而这里的这个方法就是传递消息方法,当Handler接受到这个消息是就开启线程的耗时操作,当然也可以用这个方法来区分线程的队列。

 start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                progressbar.setVisibility(progressbar.VISIBLE);
                handler.post(update);
            }
        });

然后这句代码就是按钮点击后的动作,先是显示进度条然后再开启子线程进行耗时操作。

案例三:

                                            

左边是点击执行按钮之后显示呵呵。。右边的是点击执行按钮之前的屏幕显示嘻嘻

这个例子相对来说很简单,主要是通过子线程来更新UI

我们还是来看看主要的java代码吧!

在这里还是同样地创建了一个Handler对象,这里就用到了上个例子我说过的当msg.wht=0x123的时候执行下面的语句,textview.setText()方法,把TextView控件的内容变为呵呵。。!

Handler handler = new Handler() {
        // 该方法运行在主线程中
        // 接收到handler发送的消息,对UI进行操作
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            if (msg.what == 0x123) {
                textView.setText("呵呵。。");
            }
        }
    };

这里点击按钮执行setButton()方法,这里用到了封装的技术,学过java的,我就不多介绍了吧!

 button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setButton();
            }
        });

我们来看看setButton这个方法的代码,就是创建一个Thread()方法来进行耗时操作,这里我们可以看到handler.senEmptyMessage()这个方法这里就是给队列放松消息,当Handler对象接收到这个消息后就会更新UI。

 private void setButton(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 在此执行耗时工作,执行完毕后调用handler发送消息
                try {
                    Thread.sleep(6000);//睡眠6秒 模拟执行耗时任务
                    handler.sendEmptyMessage(0x123);//发送消息
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }


案例四:

                                  

这个案例是倒计时5秒后自动跳转到另一个activity,这个例子对于上面的例子来说难度会大一些,主要是看跳转前的java代码来实现这个效果。

 private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == UPDATE){
                textView.setText(String.valueOf(msg.arg1));
            }
        }
    };

这句代码我相信大家应该都清楚了其中的作用了吧!我们主要是来看看begin()这个方法里面的代码。

public void begin(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=5;i>0;i--){
                    Message msg = new Message();
                    msg.what = UPDATE;
                    msg.arg1 = i;
                    handler.sendMessage(msg);
                    try {
                        Thread.sleep(1000);//休眠1秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //计时结束后跳转到其他界面
               startIntent();
                //添加finish方法在任务栈中销毁倒计时界面,使新开界面在回退时直接退出而不是再次返回该界面
                finish();
            }
        }).start();
    }

可以看到这里用了for循环来实现倒计时的效果,然后定义一个msg.arg1参数用这个参数传递给外面显示在屏幕上数字,这里定义了msg.what=UPDATE,用这个来通知队列用handler.senMessage()方法将msg对象发送给Handler对象,当for循环完了执行startIntent()方法来实现跳转的效果,这里的这个方法是我封装的一个方法,然后finish()方法销毁这个Activity,这里还要给UPDATE这个参数进行赋值。


然后下面就是这个程序的XML布局文件的代码和java代码了。

主页面的XML页面布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:text="@string/TextView"
        android:textSize="30dp"
        android:layout_gravity="center"
        android:layout_width="230dp"
        android:layout_height="60dp" />
    <Button
        android:id="@+id/btn1"
        android:text="@string/button1"
        android:textSize="20dp"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"
        android:layout_width="200dp"
        android:layout_height="60dp" />
    <Button
        android:id="@+id/btn2"
        android:text="@string/button2"
        android:textSize="20dp"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"
        android:layout_width="200dp"
        android:layout_height="60dp" />
    <Button
        android:id="@+id/btn3"
        android:text="@string/button3"
        android:textSize="20dp"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"
        android:layout_width="200dp"
        android:layout_height="60dp" />
    <Button
        android:id="@+id/btn4"
        android:text="@string/button4"
        android:textSize="20dp"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"
        android:layout_width="200dp"
        android:layout_height="60dp" />

</LinearLayout>

主页面的java代码:

package com.example.handler;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {
    private Button button1;
    private Button button2;
    private Button button3;
    private Button button4;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mainlayout);
        button1 = (Button) findViewById(R.id.btn1);
        button2 = (Button) findViewById(R.id.btn2);
        button3 = (Button) findViewById(R.id.btn3);
        button4 = (Button) findViewById(R.id.btn4);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setButton1();
            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setButton2();
            }
        });
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setButton3();
            }
        });
        button4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setButton4();
            }
        });
    }
    private void setButton1(){
        Intent intent = new Intent();
        intent.setClass(MainActivity.this,FirstDemo.class);
        this.startActivity(intent);
    }
    private void setButton2(){
        Intent intent = new Intent();
        intent.setClass(MainActivity.this,SecondDemo.class);
        this.startActivity(intent);
    }
    private void setButton3(){
        Intent intent = new Intent();
        intent.setClass(MainActivity.this,ThirdDemo.class);
        this.startActivity(intent);
    }
    private void setButton4(){
        Intent intent = new Intent();
        intent.setClass(MainActivity.this,FourthDemo.class);
        this.startActivity(intent);
    }
}

案例一的XML页面布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/TextView"
        android:layout_width="match_parent"
        android:layout_height="280dp" />
    <Button
        android:id="@+id/btn_start"
        android:text="@string/btn_start"
        android:textSize="20dp"
        android:layout_width="match_parent"
        android:layout_height="60dp" />
    <Button
        android:id="@+id/btn_end"
        android:text="@string/btn_end"
        android:textSize="20dp"
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="60dp" />
</LinearLayout>

案例一的java代码:

package com.example.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class FirstDemo extends Activity {
    private Button button_start;
    private Button button_end;
    private TextView textview;
    Handler handler = new Handler();
    Runnable update = new Runnable() {
        @Override
        public void run() {
            textview.append("\n更新中......");
            handler.postDelayed(update,1000);
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.firstlayout);
        button_start = (Button) findViewById(R.id.btn_start);
        button_end = (Button) findViewById(R.id.btn_end);
        textview = (TextView) findViewById(R.id.TextView);
        button_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.post(update);
            }
        });
        button_end.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.removeCallbacks(update);
            }
        });
    }
}

案例二的XML的页面布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_width="fill_parent"
        android:layout_height="100dip"
        android:layout_alignParentTop="true"
        style="?android:attr/progressBarStyleHorizontal"
        android:visibility="gone"
        />
    <Button
        android:id="@+id/btn_start"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="80dp"
        android:layout_alignParentBottom="true"
        android:text="@string/btn_start"
        />
</LinearLayout>

案例二的java代码:

package com.example.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;

public class SecondDemo extends Activity {
    private ProgressBar progressbar;
    private Button start;
    int Max = 200;
    Handler handler = new Handler(){
        public void handleMessage(Message msg) {
            progressbar.setProgress(msg.arg1);
            handler.post(update);
        }
    };
    Runnable update = new Runnable() {
        int i = 0;
        @Override
        public void run() {
            i += 10;
            Message msg = handler.obtainMessage();
            msg.arg1 = i;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            handler.sendMessage(msg);
            if(i == progressbar.getMax())
                handler.removeCallbacks(update);
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.secondlayout);
        progressbar = (ProgressBar) findViewById(R.id.progressbar);
        start = (Button) findViewById(R.id.btn_start);
        progressbar.setMax(Max);
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                progressbar.setVisibility(progressbar.VISIBLE);
                handler.post(update);
            }
        });
    }
}

案例三的XML页面布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/TextView"
        android:layout_marginTop="120dp"
        android:layout_gravity="center"
        android:textSize="30dp"
        android:layout_width="150dp"
        android:layout_height="50dp" />
    <Button
        android:id="@+id/btn_start"
        android:text="执行"
        android:layout_marginTop="50dp"
        android:layout_gravity="center"
        android:layout_width="120dp"
        android:layout_height="60dp" />

</LinearLayout>

案例三的java代码:

package com.example.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class ThirdDemo extends Activity {
    private TextView textView;
    private Button button;
    Handler handler = new Handler() {
        // 该方法运行在主线程中
        // 接收到handler发送的消息,对UI进行操作
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            if (msg.what == 0x123) {
                textView.setText("呵呵。。");
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.thirdlayout);
        textView = (TextView) findViewById(R.id.TextView);
        button = (Button) findViewById(R.id.btn_start);
        textView.setText("嘻嘻");
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setButton();
            }
        });
    }
    private void setButton(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 在此执行耗时工作,执行完毕后调用handler发送消息
                try {
                    Thread.sleep(6000);//睡眠6秒 模拟执行耗时任务
                    handler.sendEmptyMessage(0x123);//发送消息
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

案例四还没有跳转的XML页面布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/TextView"
        android:layout_marginTop="210dp"
        android:layout_marginLeft="160dp"
        android:layout_width="60dp"
        android:layout_height="70dp"
        android:textSize="60dp" />

</LinearLayout>

案例四跳转后的XML页面布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/TextView"
        android:textSize="30dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

案例四没有跳转的java代码:

package com.example.handler;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
/*
 * Handler:
 * 1 处理的消息对象就是Message,理解为要传递的消息数据的封装对象
 * Message what : 标记,用来区分多个消息
 * Message arg1,arg2 : 用来传递int类型的数据
 * Message obj : 可以传递任何类型的对象(Object)
 */
public class FourthDemo extends AppCompatActivity {
    public static final int UPDATE = 0x1;
    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fourthlayout);
        textView = (TextView) findViewById(R.id.TextView);
        begin();
    }
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == UPDATE){
                textView.setText(String.valueOf(msg.arg1));
            }
        }
    };
    public void begin(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=5;i>0;i--){
                    Message msg = new Message();
                    msg.what = UPDATE;
                    msg.arg1 = i;
                    handler.sendMessage(msg);
                    try {
                        Thread.sleep(1000);//休眠1秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //计时结束后跳转到其他界面
               startIntent();
                //添加finish方法在任务栈中销毁倒计时界面,使新开界面在回退时直接退出而不是再次返回该界面
                finish();
            }
        }).start();
    }
    private void startIntent(){
        Intent intent = new Intent();
        intent.setClass(FourthDemo.this,FourthDemo2.class);
        startActivity(intent);
    }
}

案例四跳转后的java代码:

package com.example.handler;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class FourthDemo2 extends Activity {
    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fourth2layout);
        textView = (TextView) findViewById(R.id.TextView);
        textView.setText("成功完成自动跳转");
    }
}

这次的例子就讲完了,其实要想更加容易记住就得多动手!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值