第一行代码 第10章 服务 -- Handler与AsyncTask

从广播一下跳到服务这章。。。已然没什么耐心了~~~
好吧。。。继续
啥是服务?
在Android系统中,服务是实现应用程序后台运行的解决方案。
1、服务依赖于创建它的应用程序,当这个应用程序被杀死时,所有依赖于该进程的服务也会停止运行。
2、服务的代码默认运行在主线程中,因此需要在服务的内部手动创建子线程,并在子线程中执行具体的任务,避免阻塞主线程。

一、创建线程的方式
方式1、新建一个类,继承Thread,重写父类的run()方法,在run()方法执行代码逻辑。

 class MyThread extents Thread{

    @Override
    pubilc void run(){
        // 处理具体的逻辑

    }
 }

启动线程:new出MyThread的实例,然后调用它的start()方法。这样run()方法中的代码就会在子线程中运行了。

new MyThread().start();

使用继承的方式,耦合性高,所以更多时候选择使用实现Runnable接口的方式来定义一个线程

啥是耦合性?
这个解释起来确实很麻烦,网上也有一堆的专业解释
这边我也引入网上举的例子来说明一下:(忘记哪个网站说的了)
有一百人分成10个团队做开发
你写了一个类A,供其他人调用,怎么办?
简单的方法就是把这个类打成jar包,然后给他们
他们就A a = new A();
然后调用a的方法。

但是有一天,A类升级了,怎么办?
再打jar包,再给其他9个组每个组发一份,告诉他们,替换一下以前的jar包。
有可能你的a中,方法签名还发生了变化,那么他们就得重新改代码来适应你新的jar包了。
如果这样的事频繁发生呢,那么你就等着挨骂吧。
这就是紧耦合,他们的程序紧密地耦合着你的程序。

如果是松耦合的话,我想我可能会定义一个接口给他们,然后IOC的方式将实现类给他们,
最好是远程的通过webservice的方式进行调用,这样我的A更新了,只需要切换掉远程的A的实现类,他们根本啥也不知道,啥也不用改,就更新了功能,怎么样,是不是很方便?

这就是松耦合

方式2:使用Runnable接口方式

 class MyThread implements Runnable{

    @Override
    pubilc void run(){
        // 处理具体的逻辑

    }
 }

启动线程:

 new Thread(new MyThread()).start();

方式3:使用匿名类的方式

 new Thread(new Runnable(){

    @Override
    pubilc void run(){
        // 处理具体的逻辑

    }
 }).start();

二、异步消息处理机制 – Handler的基本用法

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final int CHNAGE_TEXT = 1;
    private int i = 0;

    private TextView tvShowText;
    private Button btnChangeText;

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case CHNAGE_TEXT:
                    tvShowText.setText("you click button: "+msg.arg1+" times");
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvShowText = (TextView)findViewById(R.id.tvShowText);
        btnChangeText = (Button)findViewById(R.id.btnChangeText);

        btnChangeText.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btnChangeText:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message message = new Message();
                        message.what = CHNAGE_TEXT;
                        message.arg1 = ++i;
                        handler.sendMessage(message);
                    }
                }).start();
                break;
            default:
                break;

        }
    }
}

上述的示例中,当点击按钮时创建并启动了一个线程。如果在线程的run()方法中直接更新text view(tvShowText.setText(“you click button!”);),则会报错。
因为Android不允许在子线程中进行UI更新操作
所以使用的handle方式。


三、解析异步消息处理机制
Android中的异步消息处理主要由4个部分组成:Message、Handler、MessageQueue、和Looper.

1、Message
Message是在线程之间传递的消息。它可以在内部携带少量的信息,用于在不同的线程之间交换数据。使用what字段、arg1和arg2字段来携带整型数据;使用obj字段携带一个object对象。

2、Handler
Handler主要用于发送和处理消息的。发送消息一个使用Handler的sendMessage()方法。发出的消息最终会传递到Handler的handleMessage()方法中。

3、MessageQueue
MessageQueue是消息队列,主要用于存放所有通过Handler发送的消息。每个线程中只会有一个MessageQueue对象。

4、Looper
Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环中。当发现MessageQueue中存放一条消息,就会将它取出,并传送到Handler的handleMessage()方法中。每个线程也只会有一个Looper对象。

对上述示例解析:
首先在主线程中创建一个Handler对象,并重写handleMessage()方法;然后当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler将消息发送出去。之后这条消息就会被添加到MessageQueue的队列中等待被处理,而Looper会一直尝试从MessageQueue中取出待处理的消息,最后分发回Handler的handleMessage()方法中。


四、AsyncTask的基本用法
AsyncTask背后的实现原理也是基于异步消息处理机制的,只是做了封装而已。

AsyncTask是一个抽象类,通过创建一个子类去继承它来使用。在继承时,可以为AsyncTask类指定3个泛型参数:
1、Params:在执行AsyncTask时需要传入的参数,可用于在后台任务中使用

2、Progress:后台执行任务时,如果需要在界面上显示当前的进度,则可以使用这里指定的泛型作为进度单位。

3、Result:当任务完成后,如果需要对结果进行返回,则可以使用这里指定的泛型作为返回值类型。

一个最简单的自定义AsyncTask如下:

 class DownloadTask extents AsyncTask<Void, Integer, Boolean>{

 }

这第一个泛型参数指定为Void,表示在执行AsyncTask时不需要传入参数给后台任务。
第二个泛型参数指定为Integer,表示使用整型数据来作为进度显示单位。
第三个泛型参数指定为Boolean,表示使用布尔型数据来反馈执行结果。

重写AsyncTask中的几个方法
1、onPreExecute()
这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作。

2、doInBackground(Params…)
这个方法中的所有代码都会在子线程中运行,需要在这个方法中处理耗时任务,任务完成后可以通过return语句来将任务的执行结果返回。
如果AsyncTask的第三个泛型参数指定的是Void,则不会返回任务的执行结果。
当需要更新UI元素时,可以调用publishProgress(Progress…)方法来完成,这样就能够从子线程切换到主线程了。

3、onProgressUpdate(Progress…)
当在后台任务中调用了publishProgress(Progress…)方法后,这个方法就会被调用。
该方法中携带的参数就是从后台任务中传递过来的,利用这个参数中的数值就可以更新UI了

4、onPostExecute(Result)
当后台任务执行完毕,并通过return返回时,这个方法就会被调用。
返回的数据可作为参数传递到这个方法中,可以利用返回的数据进行UI操作。

因此,一个完整的AsyncTask就可以写成如下方式:


 class DownloadTask extents AsyncTask<Void, Integer, Boolean>{

        @Override
        protected void OnPreExecute(){

        }

        @Override
        protected Boolean doInBackground(Void...params){
            return true;
        }

        @Override
        protected void onProgressUpdate(Integer...values){

        }

        @Override
        protected void onPostExecute(Boolean result){

        }
 }

简单来说,使用AsyncTask的诀窍是:
在doInBackground()方法中执行耗时任务,
在onProgressUpdate()方法中更新UI,
在onPostExecute()方法中执行任务的收尾工作。

启动任务:
new DownloadTask().execute();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值