Android学习笔记9---Handler

来源:互联网 发布:尚硅谷java视频教程 编辑:程序博客网 时间:2024/06/07 00:38

what is handler?

 因为android的UI操作不是线程安全的,只有主线程才能对UI进行操作,如果我们想对UI进行操作,那么就需要用到handler消息处理机制


消息处理机制的步骤:

Step1.在Activity中创建Handler

Step2.在子线程中用handler发消息

Step3.在handlerMessage方法中处理消息


以下内容参见《Android》从入门到精通 清华大学出版社(明日科技编著)

通过Thread类构造方法创建线程

MainActivity.java:

Thread thread = new Thread(new Runnable() {            @Override            public void run() {                try {                    Thread.sleep(1500);                    Intent intent = new Intent(MainActivity.this,Main2Activity.class);                    startActivity(intent);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        });        thread.start();


使用线程做一个播放背景音乐小demo

package amy.com.playbgsound;import android.media.MediaPlayer;import android.renderscript.RenderScript;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;public class MainActivity extends AppCompatActivity {    private Thread thread;    private static MediaPlayer mp = null;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Button button = (Button) findViewById(R.id.button1);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //设置按钮不可用                ((Button)v).setEnabled(false);                thread = new Thread(new Runnable(){                    @Override                    public void run() {                        playBGSound();                    }                });                thread.start();            }        });    }    private void playBGSound(){        if(mp!=null) {//释放资源            mp.release();        }        mp = MediaPlayer.create(MainActivity.this,R.raw.cd);        mp.start();        //位MediaPlayer添加播放完成事件监听器        mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {            @Override            public void onCompletion(MediaPlayer mp) {                try {                    Thread.sleep(1500);                    playBGSound();                }catch (InterruptedException e) {                    e.printStackTrace();                }            }        });    }    @Override    protected void onDestroy() {        if(mp!=null) {            mp.stop();            mp.release();            mp = null;        }        if(thread!=null) {            thread = null;        }        super.onDestroy();    }}

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="amy.com.playbgsound.MainActivity">    <FrameLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content">        <Button            android:id="@+id/button1"            android:layout_width="400dp"            android:layout_height="fill_parent"            android:text="点我播放背景音乐"            android:textSize="40dp"            android:textColor="#ffffff"            android:background="#000000"            tools:layout_editor_absoluteY="8dp"            tools:layout_editor_absoluteX="8dp" />    </FrameLayout></android.support.constraint.ConstraintLayout>


Handler消息传递机制

循环者Looper简介

下图是Thread-Looper-MessageQueue三者之间的关系


Looper对象是用来为线程开一个消息循环的,从而操作MessageQueue,默认情况下,Android中创建的线程是没有开消息循环的,except for main Thread.系统会自动为主线程创建Looper对象,开启消息循环。

在主线程中:Handler handler = new Handler();是不会有错的,But在非主线程中就又bug了。

使用非主线程创建一个Handler对象

LooperThread.java

package amy.com.handlertest;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.util.Log;/** * Created by Administrator on 2017/9/23/023. */public class LooperThread extends Thread {    public Handler handler1;    @Override    public void run() {        super.run();        //初始化Looper        Looper.prepare();        //实例化一个Handler对象        handler1 = new Handler() {            public void handleMessage(Message msg) {                Log.e("Looper","1111111111111111111");            }        };        Message m = handler1.obtainMessage();//获取一个消息        handler1.sendMessage(m);        Looper.loop();    }}
MainActivity.java

在onCreate方法里面加入如下两行代码

LooperThread thread = new LooperThread();        thread.start();
运行效果


Looper类提供的常用方法有:


PS:Looper.loop()后的代码不会被执行,loop内部循环。

只有在调用了Handler.getLooer().quit()方法后,loop方法才会终止,后面的代码才会被执行。


Handler简介

Handler,消息处理类,允许发送和处理Message或Runnable接口对象到它所在线程的MessageQueue中。Handler主要有两个作用:

作用1.

将Message或Runnbale应用post()或者sendMessage()方法发送到MessageQueue中,在发送时可以指定延迟时间,发送时间以及要携带的Bundle数据。当MessageQueue循环到该Message时,就调用相应的Handler对象的handlerMessage()方法对其进行处理

作用2.

在子线程中与主线程进行通信,也就是在工作线程中与UI线程进行通信。

PS:在一个线程中,只能有一个Looper和MessageQueue,但是有多个Handler,而且这些Handler可以共享同一个Looper和MessageQueue


Handler类提供的常用方法


消息类Message

省略n段描述。。。。

获取网络图片显示到ImageView中小demo

MainActivity.java:

package com.amy.handlertest2;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.widget.ImageView;import java.io.IOException;import java.io.InputStream;import java.net.URL;import java.net.URLConnection;public class MainActivity extends AppCompatActivity {    private ImageView iv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        iv = (ImageView) findViewById(R.id.imageView1);        new Thread(new Runnable() {            Bitmap bitmap = null;            @Override            public void run() {                //从网络中获取图片                //bitmap = getPicture("http://localhost:8088/MUKE.jpg");写这个地址是访问不到的                bitmap = getPicture("http://10.150.16.216:8088/MUKE.jpg");                Log.e("bitmap",bitmap.toString());                try {                    Thread.sleep(1500);                } catch (InterruptedException e) {                    e.printStackTrace();                }                //发送一个Runnable对象                iv.post(new Runnable() {                    @Override                    public void run() {                        iv.setImageBitmap(bitmap);                    }                });            }        }).start();//        thread.start();    }    /**     * 功能:根据网址获取图片对应的Bitmap对象     *     */    public Bitmap getPicture(String path) {        Bitmap bm = null;        try {            //创建URL对象            URL url = new URL(path);            //获取URL对象对应的链接            URLConnection conn = url.openConnection();            //打开链接            conn.connect();            //获取输入流对象            InputStream is= conn.getInputStream();            //根据输入流对象创建对应的Bitmap            bm = BitmapFactory.decodeStream(is);        } catch (IOException e) {            e.printStackTrace();        }        return bm;    }}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.amy.handlertest2.MainActivity">    <ImageView        android:id="@+id/imageView1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/pic"        /></android.support.constraint.ConstraintLayout>

在AndroidManifest.xml中加入网络访问权限:

    <uses-permission android:name="android.permission.INTERNET"/>
效果图。1.5s后界面显示网络访问的图片



后续再补充。。。。。

再来一个小demo---多彩霓虹灯

MainActivity.java

package com.amy.color;import android.content.res.Resources;import android.os.Handler;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.LinearLayout;import android.widget.TextView;import java.util.Random;public class MainActivity extends AppCompatActivity {    private Handler handler;    private static LinearLayout linearLayout;    public static TextView[] tv = new TextView[14];    int[] bgClor = new int[]{R.color.color1,R.color.color2,            R.color.color3,R.color.color4,            R.color.color5,R.color.color6,R.color.color7};    private int index = 0;//当前颜色的值    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);//        getSupportActionBar().hide();//        //就可以隐藏标题,全屏显示//        // 隐藏状态栏//        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,//                WindowManager.LayoutParams.FLAG_FULLSCREEN);        linearLayout = (LinearLayout) findViewById(R.id.ll);        int height = this.getResources().getDisplayMetrics().heightPixels;//获取屏幕高度        for (int i=0;i<tv.length;i++) {            tv[i] = new TextView(this);            tv[i].setWidth(this.getResources().getDisplayMetrics().widthPixels);//设置文本框的宽度            tv[i].setHeight(height/tv.length);            linearLayout.addView(tv[i]);//            tv[i].setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,50));//            linearLayout.addView(tv[i]);        }        //创建一个线程实现循环        Thread thread = new Thread(new Runnable() {            @Override            public void run() {                while (!Thread.currentThread().isInterrupted()) {                    Message m = handler.obtainMessage();                    m.what = 0x101;                    handler.sendMessage(m);                    try {                        Thread.sleep(new Random().nextInt(1000));                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        thread.start();        //创建一个Handler对象,在重写的handlerMessage()方法中,为每个文本框设置背景颜色        handler = new Handler() {            @Override            public void handleMessage(Message msg) {                int temp;                if(msg.what == 0x101) {                    for (int i=0;i<tv.length;i++) {                        temp = new Random().nextInt(bgClor.length);//产生一个随机数                        //去掉重复色                        if(index == temp) {                            temp++;                            if(temp == bgClor.length) {                                temp =0;                            }                        }                        index = temp;                        //为文本框设置背景                        tv[i].setBackgroundColor(getResources().getColor(bgClor[index]));//                        Log.e(tv[i].getBackground());                    }                }                super.handleMessage(msg);            }        };    }}
activity_main.xml

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.amy.color.MainActivity">    <LinearLayout        android:id="@+id/ll"        android:orientation="vertical"        android:gravity="center"        android:layout_width="match_parent"        android:layout_height="match_parent">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            app:layout_constraintBottom_toBottomOf="parent"            app:layout_constraintLeft_toLeftOf="parent"            app:layout_constraintRight_toRightOf="parent"            app:layout_constraintTop_toTopOf="parent" />    </LinearLayout></android.support.constraint.ConstraintLayout>

values/color.xml:

<?xml version="1.0" encoding="utf-8"?><resources>    <color name="colorPrimary">#3F51B5</color>    <color name="colorPrimaryDark">#303F9F</color>    <color name="colorAccent">#FF4081</color>    <color name="color1">#ffff0000</color>    <color name="color2">#ffff6600</color>    <color name="color3">#ffffff00</color>    <color name="color4">#ff00ff00</color>    <color name="color5">#ff00ffff</color>    <color name="color6">#ff0000ff</color>    <color name="color7">#ff6600ff</color></resources>
效果图:



调试期间遇到的问题,布局的设置有问题,

刚开始在LinearLayout中的布局是这样写的:

    <LinearLayout        android:id="@+id/ll"        android:layout_width="wrap_content"        android:layout_height="wrap_content">
所以,属性还是没有掌握扎实,所以导致运行出来是这个样子:



经过反复调整才出现多彩现象,想想自己也是够笨的。功夫没有用到位。。。。

Handler在这块起到了获取消息和处理消息的作用。至于怎么处理的,上面注释已经写的很清楚了,以后,针对需求不同酌情更改。

先学到这儿吧,后续有新内容,再添加。。。。



原创粉丝点击