Android学习笔记9---Handler

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

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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值