浅谈Android多线程编程

      进来这里的朋友相信是有Java线程基础的,当然,可以点击(浅谈Java多线程)回去叙叙旧。废话不多说,其实,Android多线程编并不比Java多线程编程特殊,基本都是使用相同的语法。不同的是Android多线程编程自己搞出了一套异步消息处理机制。还是先来回忆一下Java线程的基本使用吧!

//Java两种创建线程的方法
//创建一个类继承Thread
class MyThread extends Thread{
    @Override
    public void run() {
        //处理具体的逻辑
    }
}
//启动线程
//new MyThread().start();

//更多时候我们会选择使用实现Runnable接口来定义一个线程
class MyThread implements Runnable{
    @Override
    public void run() {
        //处理具体的逻辑
    }
}
//启动线程
MyThread myThread=new MyThread();
new Thread(myThread).start();

//当然,这里也有偷懒的秘籍,如果你不想专门再定义一个类去
//实现Runnable接口,也可以使用匿名类的方式(很常见的写法)。
new Thread(new Runnable(){
    @Override
    public void run() {
        //处理具体的逻辑
    }
 }).start();
      线程在Java中是处理一些耗时操作、异步、多任务下载等等。线程到了Android这个环境以后有了新的变化,Android使用线程更多的是为了用户有更好的体验,用户是有脾气的,他们不想等、不愿去思考、还不耐烦。还有就是Android在子线程中更新UI和Java更新UI有所不同。在Android SDK提供的API中,Google进行了多次封装,因此在Android里面是不能直接通过子线程去操作UI控件的,因为在Android框架里,线程是不安全的。为了解决这个问题,官方建议我们通过这Handler个类去实现UI更新。为了更好的理解,来个例子吧!在Android平台通过子线程更新UI界面:
package com.xhm.demo.providertestling;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageView;
/**
 * Created by Dell on 2017/4/16.
 */
public class MyThread extends Activity {
    private ImageView mImageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        mImageView=(ImageView) findViewById(R.id.imageView);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    //休眠三秒后切换墙纸
                    Thread.sleep(3000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                mImageView.setBackgroundResource(R.drawable.bi3);
            }
        }).start();
    }
}
布局里就一个控件,不贴代码咯!然后运行之后看到报错(程序崩溃),这样可以看出Android确实不允许在子线程中去更新UI操作的。

不着急!我们先来学习异步消息处理机制。
       Android中的异步消息处理主要由4个部分组成: Handler、Message、MessageQueue、Looper。
1.HandlerHandler顾名思义就是处理者的意思,Handler在android里负责发送和处理消息,通过它可以实现其他线程与Main线程之间的消息通讯。发送消息是使用Handler的sendMessage()方法,而发出去的消息经过一系列的辗转处理后,最终又传递到Handler的handleMessage()方法中。
2.MessageMessage是线程间通讯的消息载体。它可以携带少量的信息,用于在不同线程之间交换数据。
3.MessageQueue:MessageQueue是消息队列,先进先出,它的作用是保存有待线程处理的消息,也就是用于存放所有通过Handler发送的消息。这部分消息一直存放于消息列队中,等待被处理,每个线程只会有一个MessageQueue对象。
4.LooperLooper是每个线程中的MessageQueue管家,Looper负责管理线程的消息队列和消息循环。每个线程也只有一个Looper对象。
异步消息处理流程图:

好了,时候把上面的错误修改下咯!
package com.xhm.demo.projiect00;
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.ImageView;

public class MainActivity extends Activity {
    private ImageView mImageView;
    private static final int MESSAGE_ID=0x00000001;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView=(ImageView) findViewById(R.id.imageView);
        Button button=(Button) findViewById(R.id.buttons);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //创建一个子线程
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try{
                            //休眠三秒后切换墙纸
                            Thread.sleep(3000);
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                        //通过mHandler对象的obtainMessage()
                        //方法得到一个消息msg对象实例
                        Message msg=mHandler.obtainMessage();
                        //封装消息ID
                        msg.what=MESSAGE_ID;
                        //通过mHandler对象将消息发送出去
                        mHandler.sendMessage(msg);
                    }
                }).start();
            }
        });
    }
    //创建一个Handler局部类对象
    Handler mHandler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            //得到封装的消息ID进行匹配
            if (MESSAGE_ID==msg.what){
                //更换ImageView的背景
                mImageView.setBackgroundResource(R.drawable.bi3);
            }
        }
    };
}
<?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">

    <Button
        android:id="@+id/buttons"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="换墙纸"/>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageView"
        android:background="@drawable/bi2"/>
</LinearLayout>

效果图从左到右。当然,除了切换墙纸外,计时器也是一个很好的例子,这个作业交给大家咯!好好写代码。

Handler.post:
       handle的post方法也可以用来更新UI组件,因为handler的post方法也是在主线程运行的;使用实例代码如下:
Handler mHandler = new Handler();//首先创建一个Handler对象
private void initHandle() {
    mThread=new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(5000);//阻塞5                  mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        //更新墙纸
                          mImageView.setBackgroundResurce(R.drawable.bi3);
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });//.start()
}
使用的时候在onCreate()方法或者需要的地方调用initHandle()即可。

Handler.postDelayed:
      postDelayed和post方法大同小异,只是postDelayed比post高级一些,写法也简单一些。请看代码,一看便知。
//首先还是需要创建一个Handler对象
Handler mHandler=new Handler();
//这是一个类,当然,你可以写成一个方法,比如:Runnable mRunnable=new Runnable(){}
private class mRunnable implements Runnable {

     @Override
     public void run() {
         //更新墙纸
          mImageView.setBackgroundResurce(R.drawable.bi3);
     }
}

//这是调用postDelayed,意思是每隔五秒执行run方法
//post一样,在onCreate()方法或者你需要的地方调用
mHandler.postDelayed(new mRunnable(),5000);

//那么,如果你不想用了,可以这样操作
mHandler.removeCallbacks(runnable); 

最后:
      最后我们来一点题外话(其实是干货),扩展运动哈!话说没过几秒更新墙纸这种活,java里有个更简单的方法,我也是后来才知道的哈!往下看:
TimerTask task = new TimerTask() {
    public void run() {
        //execute the task
        //更新墙纸
        mImageView.setBackgroundResurce(R.drawable.bi3);
    }
};
Timer timer = new Timer();
//这里的意思是,从现在开始,每隔5秒执行此方法;简单的说,相当于定时器
timer.schedule(task, 5000);
好了,如果大家还有好的方法,不妨留下言,当当雷锋也是不错啊! 谢谢!

猜你喜欢

转载自blog.csdn.net/l_201607/article/details/70193592
今日推荐