Androidish组织多线程的方式(代码审查)?

时间:2012-02-08 12:14:47

标签: android multithreading

我需要下载数千个对象。我需要能够暂停和恢复下载并显示进度。我不擅长多线程,所以我编译了不同来源的代码(我简化了数学和用户界面,但保留了逻辑):

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);
        }
    }
}

这段代码工作得很好并且做了我想要的一切,但我明白它很难看并且不正确(至少在放置嵌套线程时)。那么完成同样任务的好方法是什么呢?

1 个答案:

答案 0 :(得分:0)

好的我不是一个并发专业人士,但使用一个包含4个其他线程的线程,听起来很邪恶:))

如果您只是想制作一个下载管理器,这是必要的工作。如果您使用API​​ 9或更高版本,请查看DownloadManager

否则我建议使用包含队列的简单Manager类,并处理下载的添加/删除和启动/重启/停止。如果队列中有一个元素,我会启动一个AsyncTask,它会下载该元素并在成功下载后将其从队列中删除。如果没有,它会尝试恢复。