您的位置:首页 > 其它

通过aAlarmmanger、Service、BroadcastReceiver实现定时访问任务

2017-03-15 13:52 489 查看
定时访问,后台在同样可以执行,但是不能保证进程结束后,依旧可以使用(其实是流氓行为,不应该存在),下面就介绍些有关东西

首先是AlarmManager这个类,获取实例不用说没重点说下其中的一些方法:setRepeating(),这个方法可以按照设定一个延迟时间,然后再设定一个重复循环的时间即可实现循环(定时启动)的任务,但是有一个很重要的东西,源码中有写:
public void setRepeating(int type, long triggerAtMillis,
long intervalMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, 0, operation,
null, null, null, null, null);
}


第一个传入参数是精准类型,第二个是延时时间,第三个是启动频率(定时启动),第四个是启动操作的intent,这些都很正常,但你会发现,几乎所有的AlarmManager中的方法都有调用setImpl()这个方法,不难看出,这个方法中的legacyExactLength(),比较重要,决定了是否可以精确传递(多看源码有好处),再看看这个方法:
private long legacyExactLength() {
return (mAlwaysExact ? WINDOW_EXACT : WINDOW_HEURISTIC);
}


需要获取mAlwaysExact的判断结果,其中的WINDOW_EXACT表示的精确传递,WINDOW_HEURISTIC表示因为系统休眠或者需要省电的事项来降低精确度,现在看看mAlwaysExact的获取:
/**
* package private on purpose
*/
AlarmManager(IAlarmManager service, Context ctx) {
mService = service;

mPackageName = ctx.getPackageName();
mTargetSdkVersion = ctx.getApplicationInfo().targetSdkVersion;
mAlwaysExact = (mTargetSdkVersion < Build.VERSION_CODES.KITKAT);
mMainThreadHandler = new Handler(ctx.getMainLooper());
}


可以直接看出,mAlwaysExact的获取是根据版本号的判断,KITKAT指的就是系统APi=19,也就是5.0的情况,大于5.0的时候返回值就是false,也就是不能精确传递了(也就是为和说19之后不会再精准传递的原因)那什么可以可以使用啊,有setWindow(~),和setExact(~)方法是可以精确传递的,这样就可以使用了,但是!!!!!当Api>23(6.0)的时候。。。又抓狂了https://developer.android.google.cn/training/monitoring-device-state/doze-standby.html

这个网址可以查看下确切的内容,只能使用 setAndAllowWhileIdle()或者 setExactAndAllowWhileIdle(),好吧,这样就有三个情况了,分析完了,来讲下思路:

首先进入你需要的界面初始化一个闹钟,这个闹钟就会有三种类型:Api<19,19<Api<23,Api>23三种情况分别对应的方法就是setRepeating(~)、setExact(~)、setExactAndAllowWhileIdle(~),然后你会发现=,=:啊怎么回事只有Api<19的时候才会有,所以这个时候需要定义一个广播接收器,用来接收闹铃广播,然后去启动service,对没错0.0再在service中写个闹钟,然后在发送给广播,广播在启动service然后就可以实现循环了0.0,开干:

首先创建Activity用于写主程序:
package test.ban.com.test_alarm;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

private AlarmManager alarmManager;
private long TIME_INTERVAL = 3000L;
private PendingIntent pendingIntent;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent i = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, i, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.i(TAG, "M");
alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), pendingIntent);
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Log.i(TAG, "KITKAT");
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), pendingIntent);
} else {
Log.i(TAG, "other ");
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), TIME_INTERVAL, pendingIntent);
}

}

private static final String TAG = "MainActivity";

}


启动闹钟,准备receiver的接收:当然先要注册
<receiver android:name=".AlarmReceiver"></receiver>

package test.ban.com.test_alarm;

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

/**
* Created by brander on 2017/3/15.
*/
public class AlarmReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MyService.class);
context.startService(i);
}
}


完成剩下就是service的部分了,还是要在静态注册写好:
<service android:name=".MyService"></service>

package test.ban.com.test_alarm;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.util.Log;

import java.util.Date;

/**
* Created by brander on 2017/3/15.
*/
public class MyService extends Service {
private long TIME_INTERVAL=3000L;

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

private static final String TAG = "MyService";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "time: " + new Date().
toString());
}
}).start();
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent i = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, i, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.i(TAG, "M");
alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+TIME_INTERVAL, pendingIntent);
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Log.i(TAG, "KITKAT");
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+TIME_INTERVAL, pendingIntent);
}else{
Log.i(TAG, "other ");
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), TIME_INTERVAL, pendingIntent);
}

return super.onStartCommand(intent, flags, startId);
}

}


以上完结,就这样

然后你想要实现什么请求,直接在线程里写就好了,当然,其实闹钟代码可以自己写个utils类,这就不繁琐啦。祝大家愉快(づ ̄ 3 ̄)づ
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息