Android 執行緒池模擬多執行緒併發下載任務
阿新 • • 發佈:2019-01-02
廢話不多,直接上原始碼
自定義一個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個。。。
分析:見程式碼註釋