我需要下载数千个对象。我需要能够暂停和恢复下载并显示进度。我不擅长多线程,所以我从不同的来源编译了代码(我简化了数学和UI,但保留了完整的逻辑):
public class DownloadActivity extends Activity {
private static final int MSG_FINISH = 1;
private static final int MSG_PROGRESS = 2;
private long total;
private ProgressBar progress;
private static DownloadThread thread;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.download);
progress = (ProgressBar) findViewById(R.id.progress);
total = 10000;
progress.setMax((int) total);
if (thread == null)
thread = new DownloadThread(progressHandler, 15000, 25000);
else
thread.setHandler(progressHandler);
((Button) findViewById(R.id.start_button)).setEnabled(thread.paused());
((Button) findViewById(R.id.pause_button)).setEnabled(! thread.paused());
((Button) findViewById(R.id.start_button)).setOnClickListener(startOnClickListener);
((Button) findViewById(R.id.pause_button)).setOnClickListener(pauseOnClickListener);
}
@Override
public void onBackPressed()
{
thread.pause();
thread = null;
super.onBackPressed();
}
private OnClickListener startOnClickListener = new OnClickListener() {
public void onClick(View v) {
((Button) findViewById(R.id.start_button)).setEnabled(false);
thread.unpause();
((Button) findViewById(R.id.pause_button)).setEnabled(true);
}
};
private OnClickListener pauseOnClickListener = new OnClickListener() {
public void onClick(View v) {
((Button) findViewById(R.id.pause_button)).setEnabled(false);
thread.pause();
((Button) findViewById(R.id.start_button)).setEnabled(true);
}
};
final Handler progressHandler = new Handler() {
public void handleMessage(Message msg)
{
switch (msg.what)
{
case MSG_PROGRESS:
if (progress != null)
{
long current = msg.getData().getLong("current");
progress.setProgress((int) current);
}
break;
case MSG_FINISH:
Button pause = ((Button) findViewById(R.id.pause_button));
if (pause != null)
pause.setEnabled(false);
break;
}
}
};
private class DownloadThread extends Thread
{
Handler handler;
long current;
long x;
long x2;
LinkedList<Long> pendingList;
Thread threadA;
Thread threadB;
Thread threadC;
Thread threadD;
boolean paused = true;
DownloadThread(Handler h, long x1, long x2)
{
current = 0;
this.x = x1;
this.x2 = x2;
pendingList = new LinkedList<Long>();
handler = h;
threadA = new Thread(this);
threadA.start();
threadB = new Thread(this);
threadB.start();
threadC = new Thread(this);
threadC.start();
threadD = new Thread(this);
threadD.start();
}
public void run()
{
while (! isInterrupted())
{
synchronized (this)
{
if (paused)
{
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
continue;
}
}
Long l;
synchronized (pendingList)
{
if (pendingList.size() == 0)
{
x++;
if (x > x2)
{
continue;
}
l = new Long(x);
pendingList.add(l);
synchronized (this)
{
notifyAll();
}
continue;
}
else
{
l = pendingList.poll();
if (l == null)
{
synchronized (this)
{
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
continue;
}
}
}
Object d = DownloadFactory.download(l);
if (d != null)
{
synchronized (DownloadActivity.this)
{
current++;
sendProgress();
}
}
else
{
synchronized (pendingList)
{
pendingList.add(l);
}
}
}
}
public void interrupt()
{
threadA.interrupt();
threadB.interrupt();
threadC.interrupt();
threadD.interrupt();
}
public synchronized boolean paused()
{
return paused;
}
public synchronized void pause()
{
paused = true;
}
public synchronized void unpause()
{
sendProgress();
paused = false;
notifyAll();
}
public synchronized void setHandler(Handler h)
{
handler = h;
sendProgress();
}
private void sendProgress()
{
Message msg = handler.obtainMessage(MSG_PROGRESS);
Bundle b = new Bundle();
b.putLong("current", current);
msg.setData(b);
handler.sendMessage(msg);
if (current == total)
handler.sendEmptyMessage(MSG_FINISH);
}
}
}
这段代码运行良好,可以完成我想要的一切,但我知道它很难看,而且不正确(至少在放置嵌套线程方面)。那么,完成同样任务的好方法是什么呢?
好吧,我不是并发专家,但使用包含4个其他线程的线程听起来很邪恶:)
如果你只是想制作一个下载管理器,这远远超出了必要的工作范围。如果您使用API 9或更高版本,请检查下载管理器。
否则,我建议使用一个简单的Manager类,该类包含一个队列,并处理下载的添加/删除和启动/重新启动/停止。如果队列有一个元素,我会启动一个AsyncTask,它会下载该元素,并在成功下载后将其从队列中删除。如果没有,它会尝试恢复。