美文网首页
Android 切换线程

Android 切换线程

作者: badcyc | 来源:发表于2017-10-22 20:44 被阅读0次

多线程实现3种方式:

  • 1.extends Thread/implements Runnable
  • AsyncTask
  • Rxjava 实现

实现的功能是在子线程里读取根目录的所有文件名和根目录下的一个文件的读取,并把内容显示在主线程

1.extends Thread/implements Runnable

  • extends Thread
public class MyThread extends Thread {
    public String directory= Environment.getExternalStorageDirectory().getPath().toString();
    public  String filename=directory+"/cyc.doc";
    public String filename_copy=directory+"Download/copy/facebook-144-0-027-91.apk";
    public Handler mHandler=null;
    public MyThread(Handler handler){
        mHandler=handler;
    }
    @Override
    public void run() {
        super.run();

        try {
         StringBuilder sb=new StringBuilder();
            File mfile=new File(directory);
            File[]files=mfile.listFiles();
            for (int i=0;i<files.length;i++){
                File file1=files[i];
                sb.append(file1.getPath()+"\n");
                Log.d("file:",file1.getPath());
            }
            Message message1=new Message();
            Bundle bundle1=new Bundle();
            bundle1.putString("content",sb.toString());
            message1.what=MainActivity.CONTENT;
            message1.setData(bundle1);
            mHandler.sendMessage(message1);
         BufferedReader bufferedReader=new BufferedReader(new FileReader(filename));
         String s;
         while ((s=bufferedReader.readLine())!=null){
             Message message=new Message();
             Bundle bundle=new Bundle();
             bundle.putString("content",s+"\n");
             message.what=MainActivity.CONTENT;
             message.setData(bundle);
             mHandler.sendMessage(message);
         }
         bufferedReader.close();//流关闭内存释放空间
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }

    }
}
  • implements Runable
public class MyThread2 implements Runnable {
        public String directory= Environment.getExternalStorageDirectory().getPath().toString();
        public  String filename=directory+"/cyc.doc";
        private Handler mHandler;
        public MyThread2(Handler handler){
            this.mHandler=handler;
        }
        @Override
        public void run() {
            try {
            StringBuilder sb=new StringBuilder();
            File mfile=new File(directory);
            File[]files=mfile.listFiles();
            for (int i=0;i<files.length;i++){
                File file1=files[i];
                sb.append(file1.getPath()+"\n");
                Log.d("file:",file1.getPath());
            }
            Message message1=new Message();
            Bundle bundle1=new Bundle();
            bundle1.putString("content",sb.toString());
            message1.what= MainActivity.CONTENT;
            message1.setData(bundle1);
            mHandler.sendMessage(message1);
            BufferedReader bufferedReader=new BufferedReader(new FileReader(filename));
            String s;
            while ((s=bufferedReader.readLine())!=null){
                Message message=new Message();
                Bundle bundle=new Bundle();
                bundle.putString("content",s+"\n");
                message.what=MainActivity.CONTENT;
                message.setData(bundle);
                mHandler.sendMessage(message);
            }
            bufferedReader.close();//流关闭内存释放空间
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }
        }
    }

2.AsyncTask

class MyThread_AsyncTask extends AsyncTask<Integer,Integer,String>{
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            content_tv.setText(s);
        }

        @Override
        protected String doInBackground(Integer... integers) {
            StringBuilder sb1=new StringBuilder();
            try {

                File mfile=new File(directory);
                File[]files=mfile.listFiles();
                for (int i=0;i<files.length;i++){
                    File file1=files[i];
                    sb1.append(file1.getPath()+"\n");
                    Log.d("file:",file1.getPath());
                }
                BufferedReader bufferedReader=new BufferedReader(new FileReader(filename));
                String s;
                while ((s=bufferedReader.readLine())!=null){
                    sb1.append(s+"\n");
                }
                bufferedReader.close();//流关闭内存释放空间
            }catch (FileNotFoundException e){
                e.printStackTrace();
            }catch (IOException e){
                e.printStackTrace();
            }
            return sb1.toString();
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
        }
    }

3.Rxjava

1) 创建 Observer

Observer 即观察者,它决定事件触发的时候将有怎样的行为。 RxJava 中的 Observer 接口的实现方式:

Observer<String> observer = new Observer<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

除了 Observer 接口之外,RxJava 还内置了一个实现了 Observer 的抽象类:Subscriber。
不仅基本使用方式一样,实质上,在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。所以如果你只想使用基本功能,选择 Observer 和 Subscriber 是完全一样的。它们的区别对于使用者来说主要有两点:

onStart(): 这是 Subscriber 增加的方法。它会在 subscribe 刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行), onStart() 就不适用了,因为它总是在 subscribe 所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用 doOnSubscribe() 方法,具体可以在后面的文中看到。
unsubscribe(): 这是 Subscriber 所实现的另一个接口 Subscription 的方法,用于取消订阅。在这个方法被调用后,Subscriber 将不再接收事件。一般在这个方法调用前,可以使用 isUnsubscribed() 先判断一下状态。 unsubscribe() 这个方法很重要,因为在 subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。

  1. 创建 Observable

Observable 即被观察者,它决定什么时候触发事件以及触发怎样的事件。 RxJava 使用 create() 方法来创建一个 Observable ,并为它定义事件触发规则:

  1. Subscribe (订阅)

创建了 Observable 和 Observer 之后,再用 subscribe() 方法将它们联结起来,整条链子就可以工作了

可以看到,subscriber() 做了3件事:

调用 Subscriber.onStart() 。这个方法在前面已经介绍过,是一个可选的准备方法。
调用 Observable 中的 OnSubscribe.call(Subscriber) 。在这里,事件发送的逻辑开始运行。从这也可以看出,在 RxJava 中, Observable 并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当 subscribe() 方法执行的时候。
将传入的 Subscriber 作为 Subscription 返回。这是为了方便 unsubscribe().

例子

int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
    @Override
    public void call(Subscriber<? super Drawable> subscriber) {
        Drawable drawable = getTheme().getDrawable(drawableRes));
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
}).subscribe(new Observer<Drawable>() {
    @Override
    public void onNext(Drawable drawable) {
        imageView.setImageDrawable(drawable);
    }

    @Override
    public void onCompleted() {
    }

    @Override
    public void onError(Throwable e) {
        Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
    }
});

整体代码

subscription = Observable.create(new Observable.OnSubscribe<String>() {
                    @Override
                    public void call(Subscriber<? super String> subscriber) {
                        StringBuilder sb1 = new StringBuilder();
                        try {
                            File mfile = new File(directory);
                            File[] files = mfile.listFiles();
                            for (int i = 0; i < files.length; i++) {
                                File file1 = files[i];
                                sb1.append(file1.getPath() + "\n");
                                Log.d("file:", file1.getPath());
                            }
                            BufferedReader bufferedReader = new BufferedReader(new FileReader(filename));
                            String s;
                            while ((s = bufferedReader.readLine()) != null) {
                                sb1.append(s + "\n");
                            }
                            bufferedReader.close();//流关闭内存释放空间
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        subscriber.onNext(sb1.toString());
                        subscriber.onCompleted();
                    }
                }).subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Observer<String>() {
                            @Override
                            public void onCompleted() {

                            }

                            @Override
                            public void onError(Throwable throwable) {

                            }

                            @Override
                            public void onNext(String s) {
                                content_tv.setText(s);
                            }
                        });

防止内存泄露


在onDestory()方法里进行内存回收

mHandler.removeCallbacksAndMessages(null);//移除mHandler所持有的Runnable和message

activity在关闭时把未完成的Message去掉,防止activity里有handler的引用,activity回收不掉;

if (subscription.isUnsubscribed()){
subscription.unsubscribe();//防止内存泄露
}

取消订阅,订阅不取消,activity也不能回收

if(!myThread3.isCancelled()){
myThread3.cancel(true);
}

AysncTask
由于Java内部类的特点,AsyncTask内部类会持有外部类的隐式引用。即使从代码上看我在AsyncTask里没有持有外部的任何引用,但是写在Activity里,对context仍然会有个强引用,这样如果线程超过Activity生命周期,Activity还是无法回收造成内存泄露。

那问题怎么解决呢,有两种办法:第一,在Activity生命周期结束前,去cancel AsyncTask,因为Activity都要销毁了,这个时候再跑线程,绘UI显然已经没什么意义了。第二,如果一定要写成内部类的形式,对context采用WeakRefrence,在使用之前判断是否为空。

相关文章

  • Android 切换线程

    多线程实现3种方式: 1.extends Thread/implements Runnable AsyncTask...

  • 因为我对Handler的了解,居然直接给我加了5K?!

    1 Handler是什么? android提供的线程切换工具类。主要的作用是通过handler实现从子线程切换回主...

  • Android:Handler源码解析

    1、前言 在Android中,Handler消息机制十分常见,在实现多线程消息切换的场景屡屡能看到,比如子线程切换...

  • Android 线程切换,线程池。

    在开发中,我们往往需要用到线程切换这个功能,最常见的使用场景就是,当我们需要做网络请求或者其他耗时处理时,不能在主...

  • Android线程切换之谜

    之前有写过一篇文章 记一次Handler的优化 ,当时并未详细的讲解Handler的线程切换功能。遂写下这篇文章,...

  • Android消息机制Handler

    Handler的作用 Android中从自定义线程切换到UI线程需要用到Handler,向UI线程发送消息需要Ha...

  • Android Handler机制1--Thread

    本篇文章的主要内容如下: 1、Java线程概念2、Android线程的实现3、线程的阻塞4、关于线程上下文切换5、...

  • 7.网络框架

    概念 retrofit、android-async-http、volley,帮你封装了具体的请求,线程切换以及数据...

  • 2019-06-03 面试总结

    Android基础: Handler的机制 线程切换的具体原理?Handler和Looper的对应关系?如何在...

  • 学着造轮子-RxLifeCycle

    使用RxJava的一个很大的优势就是线程的灵活切换,特别是Android开发,工作线程请求,主线程监听,这已经是最...

网友评论

      本文标题:Android 切换线程

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