Android定时任务

本章目录

  • Part One:Timer
  • Part Two:AlarmManager

Android中有很多种实现定时任务的方式,比如Timer,CountDownTimer, AlarmManager,handler和Thread。不过,主要常用的有三种:

  1. Timer(Java遗留的)
  2. Handler(下雪动画那篇使用过了)
  3. AlarmManager(Android官方推荐)

Part One:Timer

Timer是一个定时器工具,包含一系列的schedule方法用于实施定时计划。TimerTask是一个子线程的抽象类,方便在后台处理一些比较复杂的逻辑,然后利用Handler在主线程刷新UI。
下面我们通过修改先前的案例来认识一下这两个类的具体应用。

  • 首先,在activity_main.xml的cacheContainer_main布局容器中,放一个TextView,用来显示滚动文字。
        <TextView
            android:id="@+id/textView_main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:textColor="@android:color/white"
            android:layout_marginBottom="64dp"/>
  • 然后在MainActivity里面初始化这个TextView和SnowView(这里初始化SnowView是用来关闭自定义View的绘制)。
    private TextView textView;
    private SnowView snowView;
    
    private void initViews() {
        cacheContainer = findViewById(R.id.cacheContainer_main);
        animContainer = findViewById(R.id.animContainer_main);
        leftAnimImageView = findViewById(R.id.leftAnimContainer_main);
        rightAnimImageView = findViewById(R.id.rightAnimContainer_main);
        textView = findViewById(R.id.textView_main);
        snowView = findViewById(R.id.snowView_main);
    }
  • 接着初始化一段文字数组,用来以滚动的方式,不断更新显示的文字。
    private String[] contents = new String[]{"时间久了,我都快忘记我们相识多少年了,",
            "我只知道我认识你很久了,", "漫长的时间却拉不近我们的距离,",
            "一天一点爱恋,一夜一点思念,", "不想再等了,有些话想对你说。"};
  • 最后,把先前定义的openWindow方法改成switchContent,让方法名字表达的更准确一些。同时在方法里初始化Timer和TimerTask,并调用相应的方法。
    private int index = 0;//数组的索引,用于让TextView显示不同内容,初识从0开始
    private void switchContent() {
        final Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                //刷新UI必须执行在主线程
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //如果字符串数组全部显示完毕,下标清0,防止越界。同是,让自定义View停止绘制。
                        //Timer停止计划任务,并执行开窗动画
                        if (index == contents.length){
                            index = 0;
                            snowView.stopDraw();
                            initCache();
                            timer.cancel();
                        }
                        //让TextView滚动显示文字
                        textView.setText(contents[index]);
                        index++;
                    }
                });
            }
        }, 50, 4000);
    }

整个计划任务的实现逻辑并不复杂,就是不断变换数组索引坐标,让TextView显示不同的内容。
这里要重点说一下我们使用的timer.schedule(task, delay, period)的三个参数:

  1. task:TimerTask对象,就是要周期执行的任务。
  2. delay:从计时器初始化完毕后,开始启动的延迟时间。
  3. period:定时器的间隔时间。
    比如,我们的案例就是50毫秒后启动定时器,没4秒更新一下文字,文字刷新完执行动画。


    滚动文字.gif

Part Two:AlarmManager

前面提到的Timer实现定时任务的方式使用的是Java的API,大部分情况下都是满足需求的,比如本例。但是如果遇到手机锁屏或者关机,唤醒CPU执行定时任务时,就会遇到一些问题,比如闹钟。所以,官方推荐使用AlrmManager来执行定时任务。
AlarmManager的实现方式也不是很复杂,只是需要用到PendingIntent,具体步骤如下:

  • 先前的准备工作不变,只是改变switchContent方法。首先,注释掉先前写的代码,然后声明一个全局的AlarmManager
    private void switchContent() {
        alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    }

    private AlarmManager alarmManager;
  • 然后声明一个全局的PendingIntent,并设置AlarmManager的重复方式
    private void switchContent() {
        alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        Intent intent = new Intent();
        intent.setAction("action.REFRESHTEXTVIEW");
        pendingIntent = PendingIntent.getBroadcast(this,
                100, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                5000, 60000, pendingIntent);
    }

    private AlarmManager alarmManager;
    private PendingIntent pendingIntent;

其中,PendingIntent是个延迟意图对象,这里是发送广播,所以使用getBroadcast方法,也可以使用getService启动Service或者getActivity启动Activity来执行某项固定任务。getBroadcast的参数前面都好理解,最后一个参数的效果有:

  1. FLAG_CANCEL_CURRENT:如果系统中有一个相同的PendingIntent对象,那么就取消旧的,然后重新生成一个。
  2. FLAG_NO_CREATE:如果当前系统中不存在相同的PendingIntent对象,系统将不会创建该PendingIntent对象而是直接返回null。
  3. FLAG_ONE_SHOT:该PendingIntent只作用一次。在该PendingIntent对象通过send()方法触发过后,PendingIntent将自动调用cancel()进行销毁,那么如果你再调用send()方法的话,系统将会返回一个SendIntentException。
  4. FLAG_UPDATE_CURRENT:如果系统中有一个和你描述的PendingIntent对等的PendingInent,那么系统将使用该PendingIntent对象,但是会使用新的Intent来更新之前PendingIntent中的Intent对象数据,例如更新Intent中的Extras。
    另外,setRepeating也需要注意,从Android5.0开始,第二个参数triggerAtMillis(触发时间)不得低于5秒,intervalMillis(重复间隔)不得低于60秒。这两个参数如果比这两个值小,默认分别是5秒和60秒,只有大于才会生效,因为间隔太短会费电~短时间的定时任务,官方推荐使用Handler方式。
    所以,其实AlarmManager并不适合本例,这里只是讲一下用法。
    setRepeating方法的第一个参数也单独说下:
  5. AlarmManager.RTC_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟使用绝对时间,状态值为0;
  6. AlarmManager.RTC表示闹钟在睡眠状态下不可用,该状态下闹钟使用绝对时间,即当前系统时间,状态值为1;
  7. AlarmManager.ELAPSED_REALTIME_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟也使用相对时间,状态值为2;
  8. AlarmManager.ELAPSED_REALTIME表示闹钟在手机睡眠状态下不可用,该状态下闹钟使用相对时间(相对于系统启动开始),状态值为3;
  9. AlarmManager.POWER_OFF_WAKEUP表示闹钟在手机关机状态下也能正常进行提示功能,所以是5个状态中用的最多的状态之一,该状态下闹钟也是用绝对时间,状态值为4;不过本状态好像受SDK版本影响,某些版本并不支持;
  • 接下来就是自定义一个广播接收者,当接收到广播时,执行的任务:
    private class AlarmBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (index == contents.length) {
                index = 0;
                snowView.stopDraw();
                initCache();
                alarmManager.cancel(pendingIntent);//取消定时器
            }
            //让TextView滚动显示文字
            textView.setText(contents[index]);
            index++;
        }
    }
  • 最后,将广播注册即可
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("action.REFRESHTEXTVIEW");
        BroadcastReceiver receiver = new AlarmBroadcastReceiver();
        registerReceiver(receiver, intentFilter);

结果就是每隔60秒发送一个广播,广播接收器收到广播后,执行相应的任务。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容