我正在尝试制作一个在android系统上每 X 次运行一次的cron ,以便它调用我制作的服务。
我想做的cron的功能如下:
- 无论应用程序是否正在运行,都运行(部分使用OnBootReceiver完成)
- 在设备重新启动时运行(我已经完成,请参阅下面的OnBootReceiver代码)
- 每 X时间间隔运行一次(例如每10分钟)
- 如果在激活 cron 时执行服务时没有连接
Receiver
,则激活连接,以便在有连接时执行服务,然后将其停用Receiver
(我已经完成了,请参见下面的ConnectivityReceiver中的代码) .
其中一些功能我已经通过单独完成它们来实现,下面我将我所拥有的代码放在下面。
连接接收器
public class ConnectivityReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
boolean noConnectivity =
intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if(!noConnectivity){
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
// only when connected or while connecting...
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
// if we have mobile or wifi connectivity...
if ((netInfo.getType() == ConnectivityManager.TYPE_MOBILE)
|| (netInfo.getType() == ConnectivityManager.TYPE_WIFI)) {
Intent i = new Intent(context, EnvioEstadisticasService.class);
startWakefulService(context, i);
// disable receiver after we started the service
disableReceiver(context);
}
}
}
}
}
/**
* Enables ConnectivityReceiver
*
* @param context
*/
public static void enableReceiver(Context context) {
ComponentName component = new ComponentName(context, ConnectivityReceiver.class);
context.getPackageManager().setComponentEnabledSetting(component,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
/**
* Disables ConnectivityReceiver
*
* @param context
*/
public static void disableReceiver(Context context) {
ComponentName component = new ComponentName(context, ConnectivityReceiver.class);
context.getPackageManager().setComponentEnabledSetting(component,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
}
航运统计服务
public class EnvioEstadisticasService extends IntentService {
private static EstadisticasDAO daoEst;
public EnvioEstadisticasService() {
super("EnvioEstadisticasService");
}
@Override
protected void onHandleIntent(Intent intent) {
//hago todas las operaciones en envio de estadisticas
// Release the wake lock provided by the WakefulBroadcastReceiver.
ConnectivityReceiver.completeWakefulIntent(intent);
}
}
启动接收器
public class OnBootReceiver extends BroadcastReceiver {
private static final String TAG = OnBootReceiver.class.getSimpleName();
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
Log.i(TAG, "EnvioEstadisService: entra en el on bootreceiver");
Intent i = new Intent(context, EnvioEstadisticasService.class);
startWakefulService(context, i);
}
}
}
最后在清单中
<!-- Cron -->
<receiver android:name=".cron.OnBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name=".cron.ConnectivityReceiver"
android:enabled="false" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<service android:name=".services.EnvioEstadisticasService"
android:exported="false"
android:enabled="true">
</service>
<!-- -->
无论应用程序的执行如何,我都设法在设备打开或重新启动时激活服务,除了在发送时控制连接问题以便能够调用另一个接收器。
无论应用程序是否正在运行,有谁知道如何让它每隔 X 间隔运行一次?
我找到了解决问题的方法,可以满足问题中描述的我希望 cron 具有的要点。
解释
在研究并希望按照@sioesi 的建议在OnBootReceiver中使用 Timer 之后,我发现它们
AlarmManager
消耗的资源更少,根据这个StackOverflow问题,使用它们更可取,因为它们在内核级别工作。在此链接中,您可以看到警报是如何定义的以及存在的不同类型。另一方面,为了保证服务操作不会进入休眠状态并且没有完成其操作,我决定同时使用
wakefulBroadcastReceiver
inConnectivityReceiver
和OnAlarmWakefulReceiver
,如此处所述。由于这些 Receiver 负责调用将执行操作的服务,因此它们在未完成操作的情况下留下来保证其正确操作并不重要。代码
我已经修改了OnBootReceiver ,以便它创建一个警报,在我的情况下, 该警报将负责每 10 分钟唤醒一次调度过程,无论应用程序是否正在运行。代码如下:
另外,为了从 警报中调用发送统计信息的服务,我创建了以下内容
Receiver
应在问题清单中添加:
ConnectivityReceiver将与问题中的相同,只是
i.putExtra(Constants.proviene, Constants.provConnectivity);
在制作意图时必须添加它才能告诉服务从哪里被调用最后,应将以下代码添加到服务
WakefulBroadcastReceiver
中,以向调用它的人表明它已完成执行操作:我想我已经非常详细地描述了它,但是如果有一些不是很清楚的地方,我会尝试通过编辑答案来尽可能地解释它。
要执行与 a 等效的任务,您必须清楚的第一件事
cronjob
是它必须是异步任务。为此,您可以查看 Android AsyncTask Android文档。重要的是这个任务总是 1 并且只有 1 个它的实例。因此你必须占据设计模式
Singleton
。您可以创建一个扩展自 的类,然后AsyncTask
创建方法。版
在您的服务中,您可以创建一个类
之后,在您的服务中,您确定接收者何时识别:
doInBackground
你的函数的任务在哪里,然后执行onPostExecute
。使用方法onProgressUpdate
是显示任务的进度,例如计数器、进度条等。我不知道它是否有必要,但你可以使用它!由于我不完全理解您的练习,因此我无法对代码非常具体,但我希望它可以指导您!
最好使用 ScheduledExecutorService 执行此操作,因为已弃用 WakefulBroadcastReceiver 类。当应用程序关闭时,计划也有效。
我将举一个例子:
此类负责在屏幕上打印吐司(这是您必须在后台执行所需操作的地方)。它会在收到警报时执行此操作。
要配置警报,您只需使用 AlarmManager 类,指示您希望它执行的 Intent 并使用 setRepeating 函数指示周期。
如果您有任何问题,请不要犹豫。一切顺利。
最常见的选项是通过ScheduledExecutorService