在 Android 中使用 JobScheduler 检测网络状态变化

Detect Network State change using JobSchedulers in Android

使用 Android N,您不能为 CONNECTIVITY_CHANGE 意图静态注册广播接收器。

来自http://developer.android.com/preview/features/background-optimization.html#connectivity-action Google 文档建议使用 Job Scheduler 来执行此任务。

是否可以使用 Android 中的作业调度程序检测网络状态变化(LTE 到 wifi),反之亦然?

是也不是。

JobInfo.Builder.setRequiredNetworkType() 方法允许您在满足特定网络条件时将作业安排到 运行。

网络类型可以是以下三个值之一:

  • JobInfo.NETWORK_TYPE_NONE: 不需要网络连接。
  • JobInfo.NETWORK_TYPE_UNMETERED未计量 WiFi 或以太网连接。
  • JobInfo.NETWORK_TYPE_ANY:任何网络连接(WiFi 或蜂窝网络)。

现在,问题是……没有 NETWORK_TYPE_CELLUAR。您不能让您的应用仅在 处于蜂窝网络时唤醒。 (你为什么要这样做?)

另一个问题... WiFi 连接可以按流量计费或不按流量计费。计量连接通常是移动热点之类的东西,这可以自动检测(热点可以发送一个特殊的 DHCP 选项),或者用户可以在每个网络的基础上从 WiFi 设置手动切换它。

所以,是的,您可以在 JobScheduler 作业上设置网络类型限制。但是,不,您没有获得所需的粒度级别。

正如@CommonsWare 所提到的,这个想法是您通常希望在网络连接未按流量计费时安排与网络相关的作业,除非您有充分的理由。 (使用 setRequiresCharging(true) 将作业推迟到交流电源可用时也是一个好主意,以节省电池电量。)

这可能不是最佳解决方案。请在投反对票之前解释原因。

我使用 GcmTaskService 使用以下代码检测网络状态变化。这是我正在开发的天气应用程序。

public class ServiceUpdateWeather extends GcmTaskService {

    private static final String TAG = ServiceUpdateWeather.class.getSimpleName();

    public static final String GCM_TAG_REPEAT_CONNECTIVITY_CHANGE = "UPDATE_WEATHER_CONNECTIVITY_CHANGE";

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onInitializeTasks() {
        //called when app is updated to a new version, reinstalled etc.
        //you have to schedule your repeating tasks again
        super.onInitializeTasks();
        if (Utilities.checkIsNougat()) {
            ServiceUpdateWeather.cancelConnectivityChange(getApplicationContext());
            ServiceUpdateWeather.scheduleConnectivityChange(getApplicationContext());
        }
    }

    @Override
    public int onRunTask(TaskParams taskParams) {
        Handler h = new Handler(getMainLooper());
        if(taskParams.getTag().equals(GCM_TAG_REPEAT_CONNECTIVITY_CHANGE)) {
            Log.i(TAG, "Connectivity changed task fired");
            h.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(ServiceUpdateWeather.this, "Updating weather", Toast.LENGTH_SHORT).show();
                    }
                });
            WeatherHelper.runNetworkConnectedUpdater(ServiceUpdateWeather.this);
        }

        return GcmNetworkManager.RESULT_SUCCESS;
    }

    public static void scheduleConnectivityChange(Context context) {
        try {
            PeriodicTask connectivityChange = new PeriodicTask.Builder()
                    //specify target service - must extend GcmTaskService
                    .setService(ServiceUpdateWeather.class)
                    //repeat every 30 seconds
                    .setPeriod(30)
                    //specify how much earlier the task can be executed (in seconds)
                    .setFlex(10)
                    //tag that is unique to this task (can be used to cancel task)
                    .setTag(GCM_TAG_REPEAT_CONNECTIVITY_CHANGE)
                    //whether the task persists after device reboot
                    .setPersisted(true)
                    //if another task with same tag is already scheduled, replace it with this task
                    .setUpdateCurrent(true)
                    //set required network state, this line is optional
                    .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
                    //request that charging must be connected, this line is optional
                    .setRequiresCharging(false)
                    .build();
            GcmNetworkManager.getInstance(context).schedule(connectivityChange);
            Log.i(TAG, "Connectivity change task scheduled");
        } catch (Exception e) {
            Log.e(TAG, "Connectivity change task failed to schedule");
            e.printStackTrace();
        }
    }

    public static void cancelConnectivityChange(Context context) {
        GcmNetworkManager.getInstance(context).cancelTask(GCM_TAG_REPEAT_CONNECTIVITY_CHANGE, ServiceUpdateWeather.class);
        Log.v(TAG, "Connectivity change task cancelled");
    }
}

这对我来说似乎工作正常。它不会像广播接收器那样立即检测连接变化。但如果网络连接可用,它每 30 秒运行一次。请务必致电

if (Utilities.checkIsNougat()) {
    ServiceUpdateWeather.cancelConnectivityChange(getApplicationContext());
    ServiceUpdateWeather.scheduleConnectivityChange(getApplicationContext());
}

在您的主要 activity onCreate 方法中首次启动应用程序以首次安排此任务。