美文网首页android面试收集Android_SpeakAndroid知识
Handler、AsyncTask、OkHttp、RxJava:

Handler、AsyncTask、OkHttp、RxJava:

作者: Ricco_F | 来源:发表于2017-06-20 14:33 被阅读447次
转载请注明原创出处,谢谢!

命令模式:Handler.post
享元模式:Message.obtain
模板方法模式:AsyncTask
责任链模式:OkHttp
建造者模式:Response、Request
原型模式:OkHttpClient
观察者模式:RxJava

分析源码,我还没那个实力,就不写了,但原理还是要知道的。如果被面试官问了,说两个就可以了,别太认真,小心hold不住!

Android中的线程通信机制:消息机制

Android 中消息模型伪代码实现?

class Message{
    Object obj;用于存储对象类型数据
    int what;表示你要做什么
    ...
}
class MessageQueue{
    Object[] messages;
    void put(Message msg){}
    Message take(){}
}
class Looper{
    MessageQueue msgQ;
    void loop(){
        while(isLoop){}
    }
    void cancel(){}
    ...
}
class Handler{
    void sendMessage(Message msg){}
    void handleMessage(Message msg){}
    ...
}

在Android系统中,主线程不可以执行耗时操作,子线程可以执行耗时却不可以直接更新UI,所以,当子线程在执行耗时操作的过程中,如果需要更新UI,则可以发出一个“消息”给主线程,当主线程收到该“消息”后,对“消息”进行处理,即更新UI,从而完成主线程和子线程的协作。
在消息机制中,会使用到:

  • Handler消息的发送者和处理者
  • Message消息的载体
  • MessageQueue消息队列,是若干条消息的容器
  • Looper轮循者

Handler

通过调用Handler对象的sendMessage(Message)方法可以在子线程中向主线程发送消息。
通过重写void handleMessage(Message)方法可以决定如何处理消息,Handler默认是运行在主线程的,所以,可以直接更新UI。

  • 使用Handler发送消息
    • boolean sendMessage(Message msg)
    • boolean sendMessageDelayed(Message msg, long delayMillis)延迟delayMillis毫秒后发出消息
    • boolean sendMessageAtTime(Message msg, long uptimeMillis)在指定的时间点发出消息,其中,参数uptimeMillis表示从Java元年(1970-01-01 00:00:00)至今经历的毫秒数
    • boolean sendEmptyMessage(int what)发送空的消息,本质上并不是空消息,而是该方法可以帮助开发者获取消息对象,使得开发者在调用该方法之前,不用手动创建消息对象,参数int what表示消息对象的what属性
    • boolean sendEmptyMessageDelayed(int what, long delayMillis)延迟delayMillis毫秒后发出空消息
    • boolean sendEmptyMessageAtTime(int what, long uptimeMillis)在指定的时间点发出消息
    • post???()系列方法
  • 处理消息的方式
    • 自定义类继承自Handler,重写void handleMessage(Message msg)方法,在该方法中决定如何处理消息
    • 自定义类实现Handler.Callback,重写boolean handleMessage(Message msg)方法,在该方法中决定如何处理消息,然后创建出自定义的对象,用于new Handler(Handler.Callback callback)构造方法的参数
    • 在获取Message对象时,使用Message类的静态方法obtain(Handler handler, Runnable callback),该方法的参数Runnable callback就是处理消息的对象
  • 消息的分发:处理消息的优先级
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

Handler类有send???()系列方法、sendEmpty???()系列方法、post???()系列方法,都可以实现发送消息,具体的使用应该根据实际情况来进行选取,在不熟练的情况下,始终使用sendMessage(Message)即可。
有3种处理消息的方式,其中,在获取Message对象时,指定Message中的Runnable callback这种方式使用相对比较麻烦,一般不推荐,至于是继承自Handler,还是实现Handler.Callback可以自由选择。

Handler在哪个线程处理消息?

在默认情况下,Handler是在主线程处理消息的,所以,可以直接更新UI。
不可以直接在子线程中创建Handler对象,必须先调用过Looper.prepare()方法,且,Looper必须调用了loop()方法才会轮循消息队列,取出消息交给Handler处理。
在默认情况下,主线程已经存在调用了prepare()和loop()方法的Looper,所以,在主线程中创建Handler对象时不需要考虑Looper的问题。
Handler在哪个线程处理消息,完全取决于该Handler对象关联到的是哪个线程的Looper对象!即:如果在子线程创建Handler,关联到的是主线程的Looper对象,该Handler会在主线程处理线程。
在没有显式的指定Looper对象时,会默认获取创建Handler对象的线程的Looper,可表现为:在哪个线程创建Handler,就在哪个线程处理消息。
如果已经显式的指定Looper对象,则由Looper对象的线程来决定在哪个线程处理消息。

Message

  • Message的常用属性有:
    • int arg1用于在消息中封装int类型的数据
    • int arg2同上
    • Object obj用于在消息中封装任意类型的数据
    • int what用于标识消息的类型,通常使用静态常量
  • Message类静态obtain()方法
    Message类静态obtain()方法可以从消息池中获取已有的、空闲的消息对象,如果消息中没有消息对象,或没有空闲的对象,则创建新的对象。
    该obtain()方法被重载了多次:
    • Message obtain()
    • Message obtain(Message msg)
    • Message obtain(Handler handler)
    • Message obtain(Handler handler, int what)
    • Message obtain(Handler handler, Runnable callback)
    • Message obtain(Handler handler, int what, Object obj)
    • Message obtain(Handler handler, int what, int arg1, int arg2)
    • Message obtain(Handler handler, int what, int arg1, int arg2, Object obj)
      如果在使用obtain()系列方法获取消息对象时指定了Handler对象,则在发送消息时,应该使用消息对象的sendToTarget()方法实现消息的发送。
      通过Handler对象的obtainMessage()系列方法也可以获取Message对象,这一系列方法的本质依然是通过Message类的静态obtain()方法实现的,所以,如果没有必要的话,就始终使用Message类的obtain()系列方法获取Message对象即可。
      永远不要new Message(),而是使用Message类的静态方法obtain()获取消息对象。

HandlerThread与IntentService

HandlerThread是一个线程类,它的作用是便捷的获取一个运行在子线程的Looper对象。
在使用HandlerThread时,必须遵循以下流程,不可调整代码的先后顺序:

  • 创建HandlerThread的线程对象
  • 开启线程
  • 获取Looper对象

使用HandlerThread的目的只是为了获取运行在子线程的Looper,进而,可以通过该Looper创建出在子线程处理消息的Handler,这样的Handler在接收到消息后可以直接执行耗时操作,当然,这样的Handler是不可以直接更新UI的。
普通的Service由于进程优先级较高,所以适合执行耗时操作,但是,Service也是运行在主线程的,所以在执行耗时操作时,也是必须开启子线程的,同时,每个Service在使用完成后应该停止。总结的结果就是:使用Service多半需要另启子线程,且使用完成后停止该Service。

  • IntentService的特点:
    • 可以不用开发者显式的开启线程而直接编写耗时任务的
    • 任务执行完毕后自我销毁的
    • 可以一次性“计划”多项任务,这些任务会依次执行
  • 使用IntentService时的注意事项:
    • 由于onHandleIntent()是运行在子线程的,所以,可以直接编写耗时任务,但是,不可以更新UI
    • 自定义的IntentService终究是Service类,必须注册
    • 自定义的IntentService的子类,必须提供无参数的构造方法,否则,系统将无法对自定义的IntentService的子类进行管理和维护
    • 基于IntentService的工作特性,这样的Service是必须通过startService()方式激活,而不可以使用bindService()方法来激活
    • 如果需要重写IntentService中的生命周期方法,切记在重写时必须调用父类的对应的生命周期方法

使用线程的方式

  • Thread + 消息机制
    • 优点:可以多项任务同时执行,使用非常灵活,可以只在Activity里使用,也可以Activity+Service使用……
    • 缺点:不宜同时开启过多的急剧消耗性能的任务,如果需要保障生命力,则还需要配合Service
  • IntentService + ResultReceiver
    • 优点:生命力顽强,多项任务依次执行
    • 缺点:代码略多 / 使用相对繁琐 / 必须有Service
  • AsyncTask
    • 优点:可以在任何位置使用,例如在Activity中,或在Service中……代码的管理非常集中,多项任务依次执行
    • 缺点:多项任务依次执行
      AsyncTask:异步任务

AsyncTask

在使用AsyncTask时,需要自定义类继承自AsyncTask,首要任务是确定3个泛型:

  • Params当执行任务之前,是否需要准备某些参数,如果需要的话,这些参数应该是哪种数据类型的
  • Progress当执行任务的过程中,是否需要以任何形式显示进度,如果需要的话,用哪种数据类型可以表示进度值
  • Result当任务执行完毕以后,是否需要获取结果,如果需要的话,获得到表示结果的数据应该是哪种数据类型的
    在自定义的AsyncTask类中,可能涉及的方法有:
  • Result doInBackground(Params... parmas)该方法是抽象方法,需要被重写,且该方法默认运行在子线程,参数是Params类型的可变参数,返回值是Result类型
  • void publishProgress(Progress... values)该方法是用于提交进度的,通常是在doInBackground()中调用的,参数提Progress类型的可变参数
  • void onProgressUpdate(Integer... values)该方法是更新进度的方法,每当publishProgress()方法被调用一次,当前onProgressUpdate()方法就会被对应的回调一次,且该方法的参数就是publishProgress()方法的参数,该方法是运行在主线程的,可以直接更新UI
  • void onPostExecute(Result result)该方法是处理结果的方法,会在doInBackground()执行完毕后被回调1次,且方法的参数是doInBackground()方法的返回值,该方法是运行在主线程的,可以直接更新UI

执行AsyncTask时,调用AsyncTask对象的execute(Params... params)方法即可
使用AsyncTask时,必须自定义子类实现继承,并且优先确定3个泛型,在这3个泛型中,不需要使用的类型可以使用Void表示,其中,doInBackground()方法是默认运行在子线程的,可以执行耗时操作,publishProgress()方法是用于在doInBackground()的执行过程中提交进度的,如果需要处理进度的显示,必须重写onProgressUpdate()方法,每次执行publishProgress()都会导致onProgressUpdate()被回调,onProgressUpdate()是运行在主线程的,可以直接更新UI,当doInBackground()执行完毕,onPostExecute()将被回调1次,该方法也是运行在主线程的,可以直接更新UI。
当需要执行任务时,先创建任务对象,然后调用execute()方法执行任务。
当需要终止任务时,可以调用任务对象的cancel(true)方法以实现终止。
假设有任务A、任务B均是继承AsyncTask实现的,那么,不管创建多少个任务A、任务B的对象,这所有的任务都将是依次执行的。

终止AsyncTask

调用任务对象的cancel(true)方法可以终止任务,实际表现为onProgressUpdate()方法和onPostExecute()方法将不再被回调,而doInBackground()并不会停止后台的运行!
不推荐使用这样的方式终止任务,在条件允许的情况下,应该使得任务自然运行结束以实现终止的效果

重点来了OkHttp、RxJava

在写OkHttp、RxJava前,我想问大家,你有多长时间没写过Handler,AsyncTask了?我在Android技术群进行询问的时候,没想到引发了一场口水仗,但有一位的观点,我很认同。

  • 如果现在项目还用Handler那么只能说项目比较老,如果是新项目,那么就是开发者不爱学习!
  • 项目不一定会用到Rx,EventBus,但是对于开发者是标配了!

当然,也有很多反对的意见。
所以,现在每当看到有关Handler,AsyncTask的技术帖,我都很反感,可这又是面试高频率题,没办法,Handler还是要了解。

OkHttp使用

compile 'com.squareup.okhttp3:okhttp:3.8.1'

public class HttpUtils {
    public static void sendOkHttpRequest(String address, Callback callback) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(address).build();
        client.newCall(request).enqueue(callback);
    }
}
HttpUtils.sendOkHttpRequest(address, new Callback() {
    @Override
    public void onResponse(Call call, Response response) throws IOException {
        final String responseText = response.body().string();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
            }
        });
    }
    @Override
    public void onFailure(Call call, IOException e) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
            }
        });
    }
});

POST请求

try {
            OkHttpClient okHttpClient = new OkHttpClient();
            RequestBody requestBody = new FormBody.Builder().add("username", "admin").add("password", "123456").build();
            Request request = new Request.Builder().url("http://www.baidu.com").post(requestBody).build();
            Response response = okHttpClient.newCall(request).execute();
            String responseText = response.body().string();
        } catch (IOException e) {
            e.printStackTrace();
        }

RxJava使用

老罗RxJava视频百度云
链接:http://pan.baidu.com/s/1pLPp4RD 密码:zx9h

public class RxUtils {

    private static final String TAG = RxUtils.class.getSimpleName();

    /**
     * 使用create方式
     */
    public static void createObserable() {
        //定义被观察者,
        Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                if (!subscriber.isUnsubscribed()) {
                    subscriber.onNext("hello");
                    subscriber.onNext("world");
                    subscriber.onCompleted();
                }
            }
        });
        Subscriber<String> showsub = new Subscriber<String>() {
            @Override
            public void onCompleted() {
                Log.i(TAG, "onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                Log.i(TAG, e.getMessage());
            }

            @Override
            public void onNext(String s) {
                Log.i(TAG, "result-->>" + s);
            }
        };
        observable.subscribe(showsub);//关联被观察者
    }
}

RxJava+OkHttp实现登录

public class LoginUtils {

    private OkHttpClient client;

    public LoginUtils() {
        client = new OkHttpClient();
    }

    /**
     * 定义了login操作,使用RxAndroid的编程思想
     * @param url
     * @param params
     * @return Json字符串
     */
    public Observable<String> login(String url,Map<String,String> params){
        return Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
               if (!subscriber.isUnsubscribed()){
                   FormBody.Builder builder = new FormBody.Builder();
                   if (params!=null&&!params.isEmpty()){
                       for(Map.Entry<String,String> entry:params.entrySet()){
                           builder.add(entry.getKey(),entry.getValue());
                       }
                   }
                   RequestBody requestBody = builder.build();
                   //构建post请求
                   Request request = new Request.Builder().url(url).post(requestBody).build();
                   client.newCall(request).enqueue(new Callback() {
                       @Override
                       public void onFailure(Call call, IOException e) {
                           subscriber.onError(e);
                       }

                       @Override
                       public void onResponse(Call call, Response response) throws IOException {
                          if (response.isSuccessful()){
                              subscriber.onNext(response.body().string());
                          }
                           subscriber.onCompleted();//访问结束
                       }
                   });
               }
            }
        });
    }
}
button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Map<String, String> params = new HashMap<String, String>();
                params.put("username", "admin";
                params.put("password", "123456");

                new LoginUtils().login(URL_LOGIN, params).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<String>() {
                    @Override
                    public void onCompleted() {
                        dialog.dismiss();
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.i(TAG, e.getMessage());
                    }

                    @Override
                    public void onNext(String s) {
                        dialog.show();
                        Log.i(TAG,s);
                       }
                    }
                });
            }
        });

相关文章

网友评论

    本文标题:Handler、AsyncTask、OkHttp、RxJava:

    本文链接:https://www.haomeiwen.com/subject/uclnqxtx.html