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