我需要下载数千个对象。我需要能够暂停和恢复下载并显示进度。我不擅长多线程,所以我编译了不同来源的代码(我简化了数学和用户界面,但保留了逻辑):
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);
}
}
}
这段代码工作得很好并且做了我想要的一切,但我明白它很难看并且不正确(至少在放置嵌套线程时)。那么完成同样任务的好方法是什么呢?
答案 0 :(得分:0)
好的我不是一个并发专业人士,但使用一个包含4个其他线程的线程,听起来很邪恶:))
如果您只是想制作一个下载管理器,这是必要的工作。如果您使用API 9或更高版本,请查看DownloadManager。
否则我建议使用包含队列的简单Manager类,并处理下载的添加/删除和启动/重启/停止。如果队列中有一个元素,我会启动一个AsyncTask,它会下载该元素并在成功下载后将其从队列中删除。如果没有,它会尝试恢复。