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

定时访问,后台在同样可以执行,但是不能保证进程结束后,依旧可以使用(其实是流氓行为,不应该存在),下面就介绍些有关东西
首先是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 ̄)づ

猜你喜欢

转载自blog.csdn.net/u013377003/article/details/62222303