Android 实现异步刷新UI,定时器等的多种实现方案

在我们开发中,我们常常会使用多线程来实现很多需求功能,譬如,在网络中访问数据,然后在界面中展示响应数据,在APP首页实现个轮播效果的viewpager,亦或是实现一个定时器的效果,定时的刷新我们的界面。。。今天我们这里稍作整理下,把能实现上述效果的可行方案归纳起来,总结如下四种方式:
方式一: AsyncTask

谷歌提供的异步工具,刷新UI神器,也是我们最常用的方式之一,很多网络请求框架也是基于它的,使用起来也很简单,贴一下代码
其中的doInbackground()方法是在子线程中调用,我们这里定义一个整形progress 然后用publishProgress()发消息给主线程,完成我们的的UI刷新,最后让线程休眠一秒钟,实现定时器的功能

private MyAsyncTask task = null;

    private boolean running = true;

    public class MyAsyncTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            while (running) {
                try {
                    // 处理耗时操作。我们这边线程休眠1秒实现秒表的效果
                    progress++;
                    publishProgress();//类似于发消息给主线程,更新UI
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            // 为主线程 实现我们刷新UI的逻辑
            reFreshUi(progress);
            super.onProgressUpdate(values);
        }

    }

然后我们定义两个方法,来实现该定时器的关停:

private void startTask() {
        stopTask();
        running = true;
        task = (MyAsyncTask) new MyAsyncTask().execute();
    }

    private void stopTask() {
        if (task != null) {
            running = false;
            task.cancel(true);
            task = null;
        }
    }

当我们要开始执行定时器的时候,只需要new一个task然后调用execute()方法。将running设为ture,此时doinbackground就会进入无限循环中。
当我们要停止刷新UI时,将running设为false,我们的task就会跳出执行循环,然后调用cancel方法就可以停下来,再次调用开始的时候,我们不能直接调用execute,因为一个task对象该方法只能调用一次,所以我们需要new 一个task然后再调用execute()方法即可。
最后,我们在我们不需要使用的时候,也要将它停下来,以防内存泄露,比如在Activity的 ondestry方法中将它停下来:


    @Override
    protected void onDestroy() {
        stopTask();
        super.onDestroy();
    }

让后我们来看看实现效果:

**方法二:
Thread +Handler**

这边我们使用自己定义的线程完成定时器操作,但是在这里,更新UI我们需要通过handler发消息给主线程,来实现我们的UI更新,代码如下:

Thread myThread = null;

    private boolean threadRun = true;

    private void startThread() {
        stopThreand();
        threadRun = true;
        myThread = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    while (threadRun) {
                        // 以下执行耗时操作,执行完成以后。。发送消息给handler更新UI
                        progress++;
                        Message message = new Message();
                        message.what = 0;
                        mHandler.sendMessage(message);
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        myThread.start();
    }

    private void stopThreand() {
        if (myThread != null) {
            threadRun = false;
            myThread.interrupt();
            myThread = null;
        }
    }
    @SuppressLint("HandlerLeak")
    public Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
            case 0:
                reFreshUi(progress);
                break;
            }
        }
    };

**方法三
TimerTask+handler**
除了我们自己开线程以外,我们还可以利用java本身提供的TimerTask代替我们开子线程,并且可以实现重复周期,不需要我们自己来休眠线程,再加上handler来更新UI:

private Timer timer = null;
private TimerTask timerTask = null;

    private void startTimer() {
        stopTimer();
        timer = new Timer();
        timerTask = new TimerTask() {

            @Override
            public void run() {
                progress++;//这边也是子线程,用于发消息更新UI
                Message message = new Message();
                message.what = 0;
                mHandler.sendMessage(message);

            }
        };
        timer.schedule(timerTask, 0, 1000);//第三个参数代表我们之前定义的休眠的1秒,即我们定义的重复周期
    }

    private void stopTimer() {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        if (timerTask != null) {
            timerTask.cancel();
            timerTask = null;
        }
    }

这边同样的的,timer.schedule方法只能调用一次,当我们听下来之后,再次开起来需要重新new对象。

**方法四
handler.postdelay**

此方法我们没有额外定义子线程,也可以实现类似于定时器的效果,我们只需要在Runable方法中反复回调handler.postdelay方法即可,在我们需要停止的时候,移除回调即可,即handler.removecallbacks(Runanble)。代码如下:

    private Runnable r = new Runnable() {

        @Override
        public void run() {
            progress++;//非子线程中,直接更新UI
            reFreshUi(progress);
            mHandler.postDelayed(r, 1000);//一秒以后,再次回调此方法

        }
    };
    private void start() {
        stop();
        mHandler.post(r);
    }

    private void stop() {
        mHandler.removeCallbacks(r);//移除回调
    }

总结,以上四种方法都可以实现定时刷新UI,如果仅仅是延迟刷新UI或者定时器,则第四种方法更为直观和方便,没有开子线程,不会出现内存泄露的问题等,如果我们需要访问网络,则使用前面几种方法。

源码下载

你可能感兴趣的:(android开发笔)