黑馬程序員-多線程-在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線程顯示文章。

目前只知道這種方式,不知道大家有沒有更好的方法?  求教


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