Android handler / 循环定时执行任务 / Timer开启循环任务

Handler概念

Handler允许你发送和处理Message和Runnable object通过关联的一个线程的MessageQueue.

Handler线程间传递消息机制

调用示例1

主函数

 myThread = new MyThread();
 Message message = mHandler.obtainMessage();
 message.what = 1;
 mHandler.sendMessage(message);

线程类 MyThread

线程类一创建,就会实例化MyHandler,线程创建后使用start(),线程就启动了吗?

private class MyThread{

        public MyThread() {
            final HandlerThread thread =
                    new HandlerThread("myThread",
                            Thread.MIN_PRIORITY);
            thread.start();
            mHandler = new MyHandler(thread.getLooper());
        }

        private class MyHandler extends Handler{
            public MyHandler(Looper looper) {
                super(looper);
            }
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case 1:
                        try {
                            Log.i(TAG, "handleMessage: " + msg.what);
                            String str = URLDecoder.decode(msg.obj.toString(), "UTF-8");
                            Log.d(TAG, "handleMessage: " + str);
                        } catch (Exception e) {
                            Log.e(TAG,e.getMessage());
                            e.printStackTrace();
                        }
                        break;
                }
            }

        }
    }

测试结果

2023-04-04 20:31:22.181 28448-32076/cn.jj.restart I/JJWorld: handleMessage: 1
2023-04-04 20:31:22.181 28448-32076/cn.jj.restart E/JJWorld: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference

线程间通信 Handler与读写锁对比1

Handler每秒传输120次消息 通过读写锁每秒传输120次消息对比。

RandomStringUtils工具类来自于此库 implementation ‘org.apache.commons:commons-lang3:3.7’

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private MyThread myThread;
    private Handler mHandler;
    private String TAG = "JJWorld";
    private Button button;
    private int interval = 0;
    private int interval2 = 0;
    private ArrayList<String> list = new ArrayList<String>();
    private ArrayList<String> list2 = new ArrayList<String>();
    private ReentrantReadWriteLock readWriteLock =new ReentrantReadWriteLock();
    private Button button2;
    private Integer period = 8;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myThread = new MyThread();
        Message message = mHandler.obtainMessage();
        message.what = 1;
        message.obj = 1;
        mHandler.sendMessage(message);
        initView();
        button.setOnClickListener(this);
        button2.setOnClickListener(this);
    }

    private void initView() {
        button = (Button) findViewById(R.id.button);
        button2 = (Button) findViewById(R.id.button2);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                new Timer().schedule(new TimerTask() {
                    @Override
                    public void run() {
                        interval++;
                        Message message = mHandler.obtainMessage();
                        message.what = 1;
                        message.obj = interval + RandomStringUtils.random(15);
                        mHandler.sendMessage(message);
                    }
                }, 0, period);
                break;
            case R.id.button2:
                new Timer().schedule(new TimerTask() {
                    @Override
                    public void run() {
                        try {
                            readWriteLock.writeLock().lock();
                            list2.add(String.valueOf(interval2++ + RandomStringUtils.random(15)));
                            if (list2.size() >= 60){
                                Message message = mHandler.obtainMessage();
                                message.what = 2;
                                message.obj = list2;
                                mHandler.sendMessage(message);
                            }
                        }catch (Exception e){

                        }finally {
                            readWriteLock.writeLock().unlock();
                        }

                    }
                }, 0, period);
                break;
        }


    }

    private class MyThread {

        public MyThread() {
            final HandlerThread thread =
                    new HandlerThread("myThread",
                            Thread.MIN_PRIORITY);
            thread.start();
            mHandler = new MyHandler(thread.getLooper());
        }

        private class MyHandler extends Handler {
            public MyHandler(Looper looper) {
                super(looper);
            }

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 1:
                        try {
                            list.add(msg.obj.toString());
                            if (list.size() >= 60) {
                                Log.d(TAG, "list: " + list);
                                list.clear();
                            }
                        } catch (Exception e) {
                            Log.e(TAG, e.getMessage());
                            e.printStackTrace();
                        }
                        break;
                    case 2:
                        try {
                            readWriteLock.readLock().lock();
                            Log.d(TAG, "list: " + list2);
                            list2.clear();
                        } catch (Exception e) {
                            Log.e(TAG, e.getMessage());
                            e.printStackTrace();
                        }finally {
                            readWriteLock.readLock().unlock();
                        }
                        break;
                }
            }

        }
    }
}

结论

使用读写锁CPU使用率稳定于 0%-1%;
使用Handler进行传输消息,CPU使用率稳定与 1%-2%;

Handler

在这里插入图片描述

读写锁

在这里插入图片描述

线程间通信 Handler与读写锁对比2

handler和锁方式性能消耗接近。
加锁情况下,创建两个线程分别每4ms修改一次NotNeedCollectData中的userId与game_scene参数,创建两外一个线程每20ms读取一次NotNeedCollectData中的userId与game_scene,CPU使用率大约为2%-3%;
使用Hanler进行消息传递,创建两个线程分别每4ms传递一次userId与game_scene参数,创建两外一个线程每20ms读取一次userId与game_scene,CPU使用率大约为3%;

测试程序如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private MyThread myThread;
    private Handler mHandler;
    private String TAG = "JJWorld";
    private Button button4;
    private Button button5;
    private Button button;
    private Button button2;
    private Button button3;
    private NotNeedCollectData notNeedCollectData;
    private int period = 4;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myThread = new MyThread();
        Message message = mHandler.obtainMessage();
        message.what = 1;
        message.obj = 1;
        mHandler.sendMessage(message);
        initView();
        button4.setOnClickListener(this);
        button5.setOnClickListener(this);
        notNeedCollectData = new NotNeedCollectData();
        button.setOnClickListener(this);
        button2.setOnClickListener(this);
        button3.setOnClickListener(this);
    }

    private void initView() {
        button4 = (Button) findViewById(R.id.button4);
        button5 = (Button) findViewById(R.id.button5);
        button = (Button) findViewById(R.id.button);
        button2 = (Button) findViewById(R.id.button2);
        button3 = (Button) findViewById(R.id.button3);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button4:
                mHandler.sendEmptyMessage(4);
                break;
            case R.id.button5:
                mHandler.sendEmptyMessage(5);
                break;
            case R.id.button:
                new Timer().schedule(new TimerTask() {
                    @Override
                    public void run() {
                        notNeedCollectData.setUserid("time:" + String.valueOf(System.currentTimeMillis()));
                    }
                }, 0, period);
                new Timer().schedule(new TimerTask() {
                    @Override
                    public void run() {
                        notNeedCollectData.setGame_scene("scene:" + String.valueOf(System.currentTimeMillis()));
                    }
                }, 0, period);
                break;
            case R.id.button2:
                new Timer().schedule(new TimerTask() {
                    @Override
                    public void run() {
                        Message message = mHandler.obtainMessage();
                        message.what = 6;
                        message.obj = String.valueOf(System.currentTimeMillis());
                        mHandler.sendMessage(message);
                    }
                }, 0, period);
                new Timer().schedule(new TimerTask() {
                    @Override
                    public void run() {
                        Message message = mHandler.obtainMessage();
                        message.what = 7;
                        message.obj = String.valueOf(System.currentTimeMillis());
                        mHandler.sendMessage(message);
                    }
                }, 0, period);
                break;
            case R.id.button3:
                mHandler.sendEmptyMessage(8);
                break;
        }


    }

    private class MyThread {
        public MyThread() {
            final HandlerThread thread =
                    new HandlerThread("jjThread",
                            Thread.MIN_PRIORITY);
            thread.start();
            mHandler = new MyHandler(thread.getLooper());
        }
        private String time;
        private String scene;

        private Runnable runnable = new Runnable() {
            @Override
            public void run() {
                mHandler.postDelayed(this, period * 5);
                Log.i(TAG, "time:" + notNeedCollectData.getUserid() + " scene:" + notNeedCollectData.getGame_scene());
            }
        };

        private Runnable runnable2 = new Runnable() {
            @Override
            public void run() {
                mHandler.postDelayed(this, period * 5);
                Log.i(TAG, "time:" + time + " scene:" + scene);
            }
        };

        private class MyHandler extends Handler {
            public MyHandler(Looper looper) {
                super(looper);
            }

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 4:
                        mHandler.post(runnable);
                        break;
                    case 5:
                        mHandler.removeCallbacks(runnable);
                        break;
                    case 6:
                        time = (String) msg.obj;
                        break;
                    case 7:
                        scene = (String) msg.obj;
                        break;
                    case 8:
                        mHandler.post(runnable2);
                        break;
                    default:

                }
            }

        }
    }
}

结果

Handler性能消耗 3%左右

在这里插入图片描述

锁性能消耗 2-3%左右
在这里插入图片描述

HandlerThread与Thread的区别

HandlerThread 内部实现了 Looper,不用再调用Looper.prepare()和Looper.loop()这些方法。
Thread需要手动调用Looper.prepare()和Looper.loop()方法。

Handler循环定时执行任务

mHandler.sendEmptyMessageDelayed(4,2000) 方式

使用mHandler.sendEmptyMessage(4)mHandler.sendEmptyMessageDelayed(4,2000) 可以实现程序的循环执行,但是无法终止程序。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private MyThread myThread;
    private Handler mHandler;
    private String TAG = "JJWorld";
    private Button button4;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myThread = new MyThread();
        Message message = mHandler.obtainMessage();
        message.what = 1;
        message.obj = 1;
        mHandler.sendMessage(message);
        initView();
        button4.setOnClickListener(this);

    }

    private void initView() {
        button4 = (Button) findViewById(R.id.button4);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {

            case R.id.button4:
                mHandler.sendEmptyMessage(4);
                break;
        }
    }

    private class MyThread {
        public MyThread() {
            final HandlerThread thread =
                    new HandlerThread("jjThread",
                            Thread.MIN_PRIORITY);
            thread.start();
            mHandler = new MyHandler(thread.getLooper());
        }

        private class MyHandler extends Handler {
            public MyHandler(Looper looper) {
                super(looper);
            }

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 4:
                        Log.i(TAG, "time: " + System.currentTimeMillis());
                        mHandler.sendEmptyMessageDelayed(4,2000);
                        break;
                }
            }

        }
    }
}

mHandler.post(runnable) 方式

通过mHandler.post(runnable) 以及 mHandler.removeCallbacks(runnable)实现代码的循环与重启。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private MyThread myThread;
    private Handler mHandler;
    private String TAG = "JJWorld";
    private Button button4;
    private Button button5;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myThread = new MyThread();
        Message message = mHandler.obtainMessage();
        message.what = 1;
        message.obj = 1;
        mHandler.sendMessage(message);
        initView();
        button4.setOnClickListener(this);
        button5.setOnClickListener(this);
        
    }

    private void initView() {
        button4 = (Button) findViewById(R.id.button4);
        button5 = (Button) findViewById(R.id.button5);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button4:
                mHandler.sendEmptyMessage(4);
                break;
            case R.id.button5:
                mHandler.sendEmptyMessage(5);
                break;
        }


    }

    private class MyThread {
        private Runnable runnable = new Runnable() {
            @Override
            public void run() {
                mHandler.postDelayed(this, 2000);
                // TODO Auto-generated method stub
                Log.i(TAG, "thread " + Thread.currentThread().getName());
                //要做的事情,这里再次调用此Runnable对象,以实现每两秒实现一次的定时器操作
                Log.e(TAG, "case 4:" + System.currentTimeMillis());
            }
        };
        
        public MyThread() {
            final HandlerThread thread =
                    new HandlerThread("jjThread",
                            Thread.MIN_PRIORITY);
            thread.start();
            mHandler = new MyHandler(thread.getLooper());
        }
        
        private class MyHandler extends Handler {
            public MyHandler(Looper looper) {
                super(looper);
            }

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 4:
                        mHandler.post(runnable);
                        break;
                    case 5:
                        mHandler.removeCallbacks(runnable);
                        break;
                }
            }

        }
    }
}

Timer开启循环任务

Timer本身会开启线程:

new Timer().schedule(new TimerTask() {
    @Override
    public void run() {
        notNeedCollectData.setUserid("time:" +String.valueOf(System.currentTimeMillis()));
    }
}, 0, period);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学知识拯救世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值