导航:首页 > 操作系统 > android定时广播

android定时广播

发布时间:2023-08-24 18:09:56

A. android 后台运行 并定时触发任务

Android中的定时任务一般有两种实现方式,一种是使用java
API里的Timer类,另一种是使用Android的Alarm机制。
这两种方式在多数情况下都能实现类似的效果,但Timer有一个明显的短板,它并不太适用与那些需要长期在后台运行的定时任务。As we
know,为了能让电池更加耐用,每种手机都会有自己的休眠策略:比如手机不用的时候智能的断开wifi连接,根据光线强弱自动调节屏幕亮度,根据手机长时间无操作时自动的让CPU进入到休眠状态等,当进入休眠状态时,这就有可能导致Timer中的定时任务无法正常运行。而Alarn机制则不存在这种情况,它具有唤醒CPU的功能,即可以保证每次需要执行定时任务的时候CPU都能正常工作。需要注意的是,这里的唤醒CPU和唤醒屏幕不是同一个概念,不能混淆。
这里我们只说Alarm机制的方式,代码如下:

public class AutoUpdateService extends Service {

@Override
public IBinder onBind(Intent intent) {

return null;
}

// 每次服务启动的时候调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {

@Override
public void run() {
doSomething();//这是定时所执行的任务
}
}).start();
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int anHour =8 * 60 * 60 * 1000;// 这是8小时的毫秒数 为了少消耗流量和电量,8小时自动更新一次
long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
Intent intent2 = new Intent(this, AutoUpdateReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent2, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);</span>

return super.onStartCommand(intent, flags, startId);
}
注意这里的AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);此处实现了定时任务。

首先我们通过调用Context的getSystemService()方法来获取AlarmManager的实例,这里需要传入的参数是ALARM_SERVICE.

接下来调用AlarmManager的set()方法就可以设置一个定时任务了,比如设定一个任务在5秒钟后执行,就可以写成 long
triggerAtTime = SystemClock.elapsedRealtime() + 5*1000;

manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime,
pi);

其中第一个参数是一个整形参数,用于指定AlarmManager的工作类型,有四种值可以选,分别是
ELAPSED_REALTIME、ELAPSED_REALTIME_WAKEUP、RTC和RTC_WAKEUP。其中ELAPSED_REALTIME表示让定时任务的触发时间从系统开机开始算起,但不会唤醒CPU。ELAPSED_REALTIME_WAKEUP同样表示让定时任务的触发时间从系统开机开始算起,但会唤醒CPU。RTC表示让定时任务的触发时间从1970年1月1日0点开始算起,但不会唤醒CPU。RTC_WAKEUP同样表示让定时任务的触发时间从1970年1月1日0点开始算起,但会唤醒CPU。使用SystemClock.elapsedRealtime()方法可以获取到系统开机至今所经历时间的毫秒数,使用System.currentTimeMillis()方法可以获取到1970年1月1日0点至今所经历时间的毫秒数。
然后看一下第二个参数,这个参数就好理解多了,就是定时任务触发的时间,以毫秒为单位。如果第一个参数使用的是ELAPSED_REALTIME或ELAPSED_REALTIME_WAKEUP,则这里传入开机至今的时间再加上延迟执行的时间。如果第一个参数使用的是RTC或RTC_WAKEUP,则这里传入1970年1月1日0点至今的时间再加上延迟执行的时间。

第三个参数是一个PendingIntent,这里我们一般会调用getBroadcast()方法来获取一个能够执行广播的PendingIntent。这样当定时任务被触发的时候,广播接收器的onReceive()方法就可以得到执行。
当然设定一个任务在10秒钟后执行还可以写成:

longtriggerAtTime =
System.currentTimeMillis() + 10 * 1000;

manager.set(AlarmManager.RTC_WAKEUP,triggerAtTime,
pendingIntent);

然后创建PendingIntent指定处理定时任务的广播接收器AutoUpdateReceiver。

import service.AutoUpdateService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class AutoUpdateReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, AutoUpdateService.class);
context.startService(i);
}

}
当启动AutoUpdateService后,就会在onStartCommand()方法里设定一个定时任务,这样每8个小时AutoUpdateReceiver的onReceive()方法就会得到执行,这样就又会启动AutoUpdateService服务,形成了永久的循环,保证服务每隔一段时间就会启动一次,这样就完成了一个长期在后台运行的服务。

我们在哪里启动服务呢,这要看具体的情况了,一般的话,当我们打开程序的时候启动一次就好了

比如写在Activity的onCrete()方法里
Intent
intent =new Intent(this,AutoUpdateService.class);

startService(intent);

最后,既然我们用到了服务和广播接收器,那么就得在AndroidManifest.xml中注册才行。

<service android:name="service.AutoUpdateService" ></service>
<receiver android:name="receiver.AutoUpdateReceiver"
></receiver>

本文参考资料:《第一行代码》

B. 22 AndroidBroadcast广播机制

广播(Broadcast)机制用于进程/线程间通信,广播分为广播发送和广播接收两个过程,其中广播接收者BroadcastReceiver便是Android四大组件之一。

BroadcastReceiver分为两类:

从广播发送方式可分为三类:

广播在系统中以BroadcastRecord对象来记录, 该对象有几个时间相关的成员变量.

广播注册,对于应用开发来说,往往是在Activity/Service中调用 registerReceiver() 方法,而Activity或Service都间接继承于Context抽象类,真正干活是交给ContextImpl类。另外调用getOuterContext()可获取最外层的调用者Activity或Service。

[ContextImpl.java]

其中broadcastPermission拥有广播的权限控制,scheler用于指定接收到广播时onRecive执行线程,当scheler=null则默认代表在主线程中执行,这也是最常见的用法

[ContextImpl.java]

ActivityManagerNative.getDefault()返回的是ActivityManagerProxy对象,简称AMP.
该方法中参数有mMainThread.getApplicationThread()返回的是ApplicationThread,这是Binder的Bn端,用于system_server进程与该进程的通信。

[-> LoadedApk.java]

不妨令 以BroadcastReceiver(广播接收者)为key,LoadedApk.ReceiverDispatcher(分发者)为value的ArrayMap 记为 A 。此处 mReceivers 是一个以 Context 为key,以 A 为value的ArrayMap。对于ReceiverDispatcher(广播分发者),当不存在时则创建一个。

此处mActivityThread便是前面传递过来的当前主线程的Handler.

ReceiverDispatcher(广播分发者)有一个内部类 InnerReceiver ,该类继承于 IIntentReceiver.Stub 。显然,这是一个Binder服务端,广播分发者通过rd.getIIntentReceiver()可获取该Binder服务端对象 InnerReceiver ,用于Binder IPC通信。

[-> ActivityManagerNative.java]

这里有两个Binder服务端对象 caller 和 receiver ,都代表执行注册广播动作所在的进程. AMP通过Binder驱动将这些信息发送给system_server进程中的AMS对象,接下来进入AMS.registerReceiver。

[-> ActivityManagerService.java]

其中 mRegisteredReceivers 记录着所有已注册的广播,以receiver IBinder为key, ReceiverList为value为HashMap。

在BroadcastQueue中有两个广播队列mParallelBroadcasts,mOrderedBroadcasts,数据类型都为ArrayList<broadcastrecord style="box-sizing: border-box;">:</broadcastrecord>

mLruProcesses数据类型为 ArrayList<ProcessRecord> ,而ProcessRecord对象有一个IApplicationThread字段,根据该字段查找出满足条件的ProcessRecord对象。

该方法用于匹配发起的Intent数据是否匹配成功,匹配项共有4项action, type, data, category,任何一项匹配不成功都会失败。

broadcastQueueForIntent(Intent intent)通过判断intent.getFlags()是否包含FLAG_RECEIVER_FOREGROUND 来决定是前台或后台广播,进而返回相应的广播队列mFgBroadcastQueue或者mBgBroadcastQueue。

注册广播:

另外,当注册的是Sticky广播:

广播注册完, 另一个操作便是在广播发送过程.

发送广播是在Activity或Service中调用 sendBroadcast() 方法,而Activity或Service都间接继承于Context抽象类,真正干活是交给ContextImpl类。

[ContextImpl.java]

[-> ActivityManagerNative.java]

[-> ActivityManagerService.java]

broadcastIntent()方法有两个布尔参数serialized和sticky来共同决定是普通广播,有序广播,还是Sticky广播,参数如下:

broadcastIntentLocked方法比较长,这里划分为8个部分来分别说明。

这个过程最重要的工作是:

BroadcastReceiver还有其他flag,位于Intent.java常量:

主要功能:

这个过主要处于系统相关的10类广播,这里不就展开讲解了.

这个过程主要是将sticky广播增加到list,并放入mStickyBroadcasts里面。

其他说明:

AMS.collectReceiverComponents

广播队列中有一个成员变量 mParallelBroadcasts ,类型为ArrayList<broadcastrecord style="box-sizing: border-box;">,记录着所有的并行广播。</broadcastrecord>

动态注册的registeredReceivers,全部合并都receivers,再统一按串行方式处理。

广播队列中有一个成员变量 mOrderedBroadcasts ,类型为ArrayList<broadcastrecord style="box-sizing: border-box;">,记录着所有的有序广播。</broadcastrecord>

发送广播过程:

处理方式:

可见不管哪种广播方式,都是通过broadcastQueueForIntent()来根据intent的flag来判断前台队列或者后台队列,然后再调用对应广播队列的scheleBroadcastsLocked方法来处理广播;

在发送广播过程中会执行 scheleBroadcastsLocked 方法来处理相关的广播

[-> BroadcastQueue.java]

在BroadcastQueue对象创建时,mHandler=new BroadcastHandler(handler.getLooper());那么此处交由mHandler的handleMessage来处理:

由此可见BroadcastHandler采用的是”ActivityManager”线程的Looper

[-> BroadcastQueue.java]

此处mService为AMS,整个流程还是比较长的,全程持有AMS锁,所以广播效率低的情况下,直接会严重影响这个手机的性能与流畅度,这里应该考虑细化同步锁的粒度。

C. android怎么发送特定广播的

起一个线程,每发一个广播后就sleep一分钟,如此循环。(或者接受系统的timechanged这个广播,这个广播好像一分钟发一次)。

Android 在发送广播时的方法 sendBroadcast(Intent)。

①:Intent myIntent = new Intent();——【创建Intent对象】

②:myIntent.setAction(String)——【设置一般的要执行的动作。参数:动作一个动作的名称,如ACTION_VIEW。应用程序的具体行动,应与供应商的包名作为前缀。】

③:myIntent.putExtra(String,Object)——【广播中额外发送的数据,String为自定义key,Object表示多种数据类型】

④:sendBroadcast(myIntent);——【发送广播】

接收广播

Android在接收广播的方法是注册一个广播接收器 registerReceiver(MyReceiver,IntentFilter)。

①:首先创建MyReceiver类(类名自定义) 继承 BroadcastReceiver类。——【创建广播接收器】

②:在MyReceiver中重写public void onReceive(Context context, Intent intent)方法。这个方法在接收到广播后触发。——【重写处理方法】

③:在Activity或者Service启动时 onCreate()、onStartCommand()等方法中实例化 MyReceiver类——【启动时实例化广播接收器】

④:IntentFilter filter = new IntentFilter();——【创建IntentFilter对象 意图过滤器】

⑤:filter.addAction(String);——【在过滤器中加入过滤条件,说明接收什么广播】

⑥:registerReceiver(cmdReceiver, filter);——【注册广播,参数为(广播接收器,意图过滤器)】

D. Android定时提醒的功能

可以用服务(服务不能被杀死或者被人为清理掉),每隔一段时间去和系统时间比较一次,当等于晚上九点的时候,可以发送广播去显示通知栏进行提示。

阅读全文

与android定时广播相关的资料

热点内容
潭州学院python 浏览:814
下载文件夹不用卸载 浏览:233
怎样删除手机内不用的英文文件夹 浏览:81
android获得屏幕宽度 浏览:302
单片机根据波形写代码 浏览:669
应届生程序员怎么投简历 浏览:721
数学建模算法与应用ppt 浏览:99
远程怎么访问端游服务器 浏览:106
打电话定位置的源码 浏览:642
即时通讯平台源码 浏览:457
安卓自助app怎么转到苹果手机 浏览:328
雅马哈回音壁不能识别源码 浏览:730
python如何移植到安卓 浏览:29
黄柱选股公式源码 浏览:639
教育系统源码达标 浏览:888
声卡驱动安装程序在哪个文件夹 浏览:62
钱还完了银行不给解压 浏览:171
linux的系统调用表 浏览:754
php怎么转换页面 浏览:548
我的世界买了服务器之后怎么开服 浏览:830