黑马程序员-多线程-在android开发中经常会遇到从子线程切换到主线程,但是频繁地切换会使代码变得很臃肿,也不好维护,想请教一下各位大牛都是怎么处理的?

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

小弟新手一枚,我先来说说我自己在项目中的做法。因为小弟只有JAVAWEB的基础所以只能使用线程池来处理线程之间的切换

1.为了使APP不出现卡顿和内存的低消耗。我是用了synchronized 和用一个Map 来限定每次只能运行一条子线程,Map 键:TAG 线程任务标记 、值:FutureTask线程任务,

2.当然线程之间的切换仍然还是使用handle,只是在等待分线程执行完,当然分线程也会由限定时间。

下面来看看代码:

public class OCThreadExecutor extends ThreadPoolExecutor {

    private Map<String,FutureTask> runnableMap;

    public OCThreadExecutor(int maxRunningThread, String poolName) {
        super(maxRunningThread, maxRunningThread, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new OCThreadFactory(poolName));
        runnableMap = new HashMap<>();
    }

以上是自定义线程池,带参的构造方法;

   static class OCThreadFactory implements ThreadFactory {

        private final String name;

        public OCThreadFactory(String name) {
            this.name = name;
        }

        public String getPoolName() {
            return name;
        }

        @Override
        public Thread newThread(@NonNull Runnable r) {
            return new OCThread(r, name);
        }

    }

    static class OCThread extends Thread {

        public OCThread(Runnable runnable, String name) {
            super(runnable, name);
            setName(name);
        }

        @Override
        public void run() {
            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
            super.run();
        }
    }
实现线程工厂;


重点来了:

 /**
     * 执行任务
     * @param task  任务对象
     * @param tag   任务唯一TAG
     */
    public void submit(FutureTask task , String tag){

        synchronized (this){
            //执行线程
            if ( !runnableMap.containsKey(tag) ){
                //如果池内没有相同的任务则可以执行
                Log.d("OCThreadExecutor", "Task submitting TAG: "+tag);
                runnableMap.put(tag, task);
                submit(task);
            }else{
                Log.d("OCThreadExecutor", "Pool: "+((OCThreadFactory)getThreadFactory()).getPoolName()+" Same task TAG. Skipped. "+tag);
            }
        }

    }
以上提交方法的tag值是为了唯一识别正在执行的线程,或者判断该线程有没有在执行。

如果没有将执行该任务,且添加进Map


下面是得到URL访问网络:

 protected NetworkHelper() {
        handler = new Handler(Looper.getMainLooper());
        httpClient = new OkHttpClient();
        threadExecutor = new OCThreadExecutor(1,"networkTHS");
    }

    public static NetworkHelper getInstance() {
        if (networkHelper == null){
            networkHelper = new NetworkHelper();
        }
        return networkHelper;
    }

    /**
     * UI 线程
     * @param runnable 在UI线程运行的任务
     */
    private void runOnUIThread(@NonNull Runnable runnable){
        boolean done = handler.post(runnable);
        while (!done){
            handler = new Handler(Looper.getMainLooper());
            runOnUIThread(runnable);
        }
    }

任务在UI线程中运行,知道任务完成,这是最让我纠结的地方,但是在项目中有没有出现过问题,可能是我现在的访问量不大吧!!  

下面是一个获取项目文章的线程方法:

 /**
     * 读取文章
     * @param onArtcleLoadCallback  读取进度回调
     * @param needToCacheImage  是否进行缓存图片网址以供主界面滚动显示
     * @param args  附带的参数
     */
    public void loadArtcles(@Nullable OnArtcleLoadCallback onArtcleLoadCallback ,@NonNull boolean needToCacheImage ,@NonNull String[] args){
        threadExecutor.submit(new FutureTask<>(new GetArtclesThread(onArtcleLoadCallback, needToCacheImage, args)),GetArtclesThread.TAG+args[2]);
    }

下载文章线程:

/**
     * 获取文章以及缓存首页滚动图片的任务
     */
    class GetArtclesThread implements Callable<String>{
        public static final String TAG = "GetArtclesThread";

        private OnArtcleLoadCallback onArtcleLoadCallback;
        private boolean needToCacheImage;
        private ArrayList<ArtclesBean> artcles = null;

        private String[] args;

        public GetArtclesThread(OnArtcleLoadCallback onArtcleLoadCallback, boolean needToCacheImage ,String[] args) {
            this.onArtcleLoadCallback = onArtcleLoadCallback;
            this.needToCacheImage = needToCacheImage;
            this.args = args;
        }

        @Override
        public String call() throws Exception {
            //先检查OKHttp是否有效
            if (httpClient == null){
                httpClient = new OkHttpClient();
            }

            //如果参数数量大于等于4,则执行请求
            if (args != null && args.length >= 4){
                try {
                    artcles = requestData();
                } catch (IOException e) {
                    Log.d(TAG, "Exception:"+e);
                    failed(null,e);
                    return null;
                }
            }else {
                failed("无效的请求参数",null);
                return null;
            }

            completed();

            return null;
        }

这是一个获取文章的任务,这个任务会在线程池中执行,在回调方法中会先执行请求文章,当获取文章完成之后才会去UI线程显示文章。

目前只知道这种方式,不知道大家有没有更好的方法?  求教


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章