1. 程式人生 > >Android 執行緒池模擬多執行緒併發下載任務

Android 執行緒池模擬多執行緒併發下載任務

廢話不多,直接上原始碼

自定義一個Adapter

public class MyAdapter extends BaseAdapter {
    private Context context;
    private List<Progress> list;
    private Object lockobj = new Object();//物件鎖

    private int complteTask = 0;//當前完成下載任務的數量

    private DownloadCompleteCall mCallback;//所有下載任務完成的回撥方法

    public interface DownloadCompleteCall {
        void downloadComplete();
    }

    public MyAdapter(Context context, List<Progress> list, DownloadCompleteCall mCallback) {
        this.context = context;
        this.list = list;
        this.mCallback = mCallback;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.progress_layout, null);
            viewHolder = new ViewHolder();
            viewHolder.progressBar = (ProgressBar) convertView.findViewById(R.id.progress);
            viewHolder.textView = (TextView) convertView.findViewById(R.id.progress_text);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        Progress curProgress = (Progress) getItem(position);
        viewHolder.textView.setText("任務" + position + ":" + curProgress.getProgress() + "%");
        viewHolder.progressBar.setProgress(curProgress.getProgress());
        return convertView;
    }

    public void update(int proBarIndex, int result) {
        if (proBarIndex < 0 || proBarIndex >= list.size()) {
            return;
        }
        Progress curPro = list.get(proBarIndex);
        curPro.setProgress(result);
        if (result == 100) {
            complteTask++;
        }
        if (complteTask == list.size()) {
            mCallback.downloadComplete();//如果完成的任務數等於總數,說明下載完成,回撥
        }
        notifyDataSetChanged();
    }

    //獲取任務列表中第一個沒有在執行的任務
    public int getProBarIndex() {
        synchronized (lockobj) {
            for (int i = 0; i < list.size(); i++) {
                if (!list.get(i).isRunning()) {
                    list.get(i).setRunning(true);
                    return i;
                }
            }
        }
        return -1;
    }

    class ViewHolder {
        TextView textView;
        ProgressBar progressBar;
    }
}

幫助類:
public class Progress {
    private int index;
    private int progress;
    private boolean running;

    public Progress(int index, int progress, boolean running) {
        this.index = index;
        this.progress = progress;
        this.running = running;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public int getProgress() {
        return progress;
    }

    public void setProgress(int progress) {
        this.progress = progress;
    }

    public boolean isRunning() {
        return running;
    }

    public void setRunning(boolean running) {
        this.running = running;
    }
}


主介面:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="模擬同時下載執行緒數:"/>

        <EditText
            android:hint="預設3個"
            android:id="@+id/countEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </LinearLayout>

    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="應用"/>

    <ListView
        android:id="@+id/listview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp">

    </ListView>
</LinearLayout>

MainActivity程式碼
public class MainActivity extends Activity implements MyAdapter.DownloadCompleteCall {
    private final static int DEFAULT_DOWNLOAD_CONTHREAD = 3;//預設併發執行緒為3
    private final static int DEFAULT_DOWNLOAD_SUM = 20;//下載任務總數

    private final static int ACTION_UPDATE_PROGRESS = 0;
    private final static int ACTION_START_DOWNLOAD = 1;

    @Bind(R.id.countEditText)
    EditText countEditText;
    @Bind(R.id.listview)
    ListView listview;

    private MyAdapter myAdapter;
    private int conThread;
    private boolean hasRunning = false;

    ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "DownloadTask#" + mCount.getAndIncrement());//執行緒的名稱
        }
    };
    BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128);//佇列最多接收128個任務的快取
    private ExecutorService threadPool;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == ACTION_START_DOWNLOAD) {
                startDownload(conThread);//開始模擬下載
            } else if (msg.what == ACTION_UPDATE_PROGRESS) {
                myAdapter.update(msg.arg1, msg.arg2);//更新adapter
            }
        }
    };

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

        initListView();
    }

    private void initListView() {
        List<Progress> progresses = new ArrayList<Progress>();
        for (int i = 0; i < DEFAULT_DOWNLOAD_SUM; i++) {
            Progress progress = new Progress(i, 0, false);
            progresses.add(progress);
        }
        myAdapter = new MyAdapter(this, progresses, this);
        listview.setAdapter(myAdapter);
    }

    @OnClick(R.id.start)
    void setThread() {
        if (hasRunning) {
            return;
        }
        conThread = DEFAULT_DOWNLOAD_CONTHREAD;
        try {
            conThread = Integer.parseInt(countEditText.getText().toString());
            if (conThread > DEFAULT_DOWNLOAD_SUM) {
                conThread = DEFAULT_DOWNLOAD_SUM;
            } else if (conThread < 0) {
                conThread = DEFAULT_DOWNLOAD_CONTHREAD;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        hasRunning = true;
        handler.sendEmptyMessage(ACTION_START_DOWNLOAD);

    }

    private void startDownload(int conThread) {
        if (threadPool != null) {
            threadPool.shutdown();
            threadPool = null;
        }
        //此時conThread個執行緒併發,如果還有任務進來,就放入sPoolWorkQueue佇列中等待執行
        threadPool = new ThreadPoolExecutor(conThread, conThread, 0, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);

        for (int i = 0; i < DEFAULT_DOWNLOAD_SUM; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    int result = 0;
                    int proBarIndex = myAdapter.getProBarIndex();
                    while (true) {
                        try {
                            //result等於100的時候,結束該下載任務
                            if (result == 100) {
                                break;
                            }
                            int sleepTime = (int) (Math.random() * 1000);
                            Thread.sleep(sleepTime);
                            result += 10;
                            Message msg = new Message();
                            msg.what = ACTION_UPDATE_PROGRESS;
                            msg.arg1 = proBarIndex;
                            msg.arg2 = result;
                            handler.sendMessage(msg);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }

    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            //shutDownThreadPool();如果想要back鍵退出應用,仍後臺下載,註釋該行
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    public void downloadComplete() {
        shutDownThreadPool();//下載完成之後,關閉執行緒池,可以看到所有下載任務完成之後,並行的執行緒DownloadTask#1到3,就結束了
    }

    private void shutDownThreadPool(){
        if (threadPool != null) {
            threadPool.shutdown();
        }
    }
}


實際執行效果:  此時設定了並行下載執行緒為10個。。。

分析:見程式碼註釋