GVKun编程网logo

android – 使用NetworkStatsManager获取移动数据使用历史记录(android获取网络数据)

8

在本文中,我们将给您介绍关于android–使用NetworkStatsManager获取移动数据使用历史记录的详细内容,并且为您解答android获取网络数据的相关问题,此外,我们还将为您提供关于A

在本文中,我们将给您介绍关于android – 使用NetworkStatsManager获取移动数据使用历史记录的详细内容,并且为您解答android获取网络数据的相关问题,此外,我们还将为您提供关于Android Browser学习十四 NetworkStateHandler网络状态监听和处理、Android Jetpack 全面学习 | WorkManager 入门、Android Jetpack库重要组件WorkManager的使用、Android Studio 对现代 WorkManager 的支持的知识。

本文目录一览:

android – 使用NetworkStatsManager获取移动数据使用历史记录(android获取网络数据)

android – 使用NetworkStatsManager获取移动数据使用历史记录(android获取网络数据)

我想知道数据使用历史,并注意到“新”android-6 NetworkStatsManager似乎是积极的(我已经使用了TrafficStats一段时间,但不会涵盖任何重启之前的任何事情).

从api文档:

NOTE: This API requires the permission PACKAGE_USAGE_STATS, which is a
system-level permission and will not be granted to third-party apps.
However, declaring the permission implies intention to use the API and
the user of the device can grant permission through the Settings
application. Profile owner apps are automatically granted permission
to query data on the profile they manage (that is, for any query
except querySummaryForDevice(int, String, long, long)). Device owner
apps likewise get access to usage data of the primary user.

我想知道聚合级别的数据使用情况,而不是使用数据的应用程序,所以我试着像这样使用它:

networkstatsmanager service = context.getSystemService(networkstatsmanager.class);

NetworkStats.Bucket bucket = 
        service.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE, null, from, to);
...

不幸的是,抛出SecurityException:

java.lang.SecurityException: NetworkStats: Neither user 10174 nor current process has android.permission.READ_NETWORK_USAGE_HISTORY.
at android.os.Parcel.readException(Parcel.java:1620)
at android.os.Parcel.readException(Parcel.java:1573)
at android.net.INetworkStatsSession$Stub$Proxy.getDeviceSummaryForNetwork(INetworkStatsSession.java:259)
at android.app.usage.NetworkStats.getDeviceSummaryForNetwork(NetworkStats.java:316)
at android.app.usage.networkstatsmanager.querySummaryForDevice(networkstatsmanager.java:100)
...

第三方应用程序不允许使用android.permission.READ_NETWORK_USAGE_HISTORY权限.所以这似乎是一个死胡同.

但是,我深入研究了内部结构,发现您可以使用内部/隐藏API执行相同的操作而无需请求任何权限:

INetworkStatsService service =
        INetworkStatsService.Stub.asInterface(
                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));

INetworkStatsSession session = service.openSession();

NetworkTemplate mobileTemplate = NetworkTemplate.buildTemplateMobileWildcard();
int fields = NetworkStatsHistory.FIELD_RX_BYTES | NetworkStatsHistory.FIELD_TX_BYTES;

NetworkStatsHistory mobileHistory = session.getHistoryForNetwork(mobileTemplate, fields);

for (int i = 0; i < mobileHistory.size(); i++) {
    NetworkStatsHistory.Entry entry = mobileHistory.getValues(i, null);
    ...
}

session.close();

我真的想对公共API做同样的事情,那么,我该怎么做呢?

解决方法:

有办法获得对NetworkStateManager的访问权限,而无需访问私有API.以下是步骤:

>在AndroidManifest.xml中声明所需的权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission
    android:name="android.permission.PACKAGE_USAGE_STATS"
    tools:ignore="ProtectedPermissions"/>

>在活动中寻求许可

android.permission.PACKAGE_USAGE_STATS不是正常的权限,不能简单地请求.要检查是否已授予权限,请检查:

AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
        android.os.Process.myUid(), getPackageName());
if (mode == AppOpsManager.MODE_ALLOWED) {
    return true;
}

要获得此权限,只需调用Intent:

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);

还需要另一个permmission:Manifest.permission.READ_PHONE_STATE.只有当你需要获得mobile data statistics时才需要它.但是,这是正常的许可,所以可以是requested as any other permission

>使用networkstatsmanager:

制作样品Github repo,展示其用途.

Android Browser学习十四 NetworkStateHandler网络状态监听和处理

Android Browser学习十四 NetworkStateHandler网络状态监听和处理

其实浏览器的网络监听和处理不过是通知给WebView进行, 没有那么多复杂的操作, 使用了NetworkStateHandler这个类来进行处理

Controller中初始化这个类

 mNetworkHandler = new NetworkStateHandler(mActivity, this); //网络变化监听

/**
 * Handle network state changes
 * 处理网络变化
 */
public class NetworkStateHandler {

    Activity mActivity;
    Controller mController;

    // monitor platform changes
    private IntentFilter mNetworkStateChangedFilter;
    private BroadcastReceiver mNetworkStateIntentReceiver;
    private boolean mIsNetworkUp;

    public NetworkStateHandler(Activity activity, Controller controller) {
        mActivity = activity;
        mController = controller;
        // Find out if the network is currently up.
        ConnectivityManager cm = (ConnectivityManager) mActivity
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = cm.getActiveNetworkInfo();
        if (info != null) {
            mIsNetworkUp = info.isAvailable(); //是否可以连接网络
        }

        /*
         * enables registration for changes in network status from http stack
         * 网络变化监听的filter 和receiver
         */
        mNetworkStateChangedFilter = new IntentFilter();
        mNetworkStateChangedFilter.addAction(
                ConnectivityManager.CONNECTIVITY_ACTION);
        mNetworkStateIntentReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals(
                        ConnectivityManager.CONNECTIVITY_ACTION)) {

                    NetworkInfo info = intent.getParcelableExtra(
                            ConnectivityManager.EXTRA_NETWORK_INFO);
                    String typeName = info.getTypeName(); //获取网络类型是wifi还是mobile
                    String subtypeName = info.getSubtypeName();//hspa 之类
                    sendNetworkType(typeName.toLowerCase(),
                            (subtypeName != null ? subtypeName.toLowerCase() : ""));

                    //网络是否连通
                    boolean noConnection = intent.getBooleanExtra(
                            ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
                    

                    onNetworkToggle(!noConnection);
                }
            }
        };

    }

    void onPause() { //在pause中解注册
        // unregister network state listener
        mActivity.unregisterReceiver(mNetworkStateIntentReceiver);
    }

    void onResume() {//在resume中注册
        mActivity.registerReceiver(mNetworkStateIntentReceiver,
                mNetworkStateChangedFilter);
    }

    /**
     * connectivity manager says net has come or gone... inform the user
     * @param up true if net has come up, false if net has gone down
     */
    void onNetworkToggle(boolean up) {
        if (up == mIsNetworkUp) {
            return;
        }
        mIsNetworkUp = up;
        WebView w = mController.getCurrentWebView();
        if (w != null) {
            w.setNetworkAvailable(up);//告诉webview 网络是否可以联通
        }
    }

    boolean isNetworkUp() {
        return mIsNetworkUp;
    }

    private void sendNetworkType(String type, String subtype) {
        WebView w = mController.getCurrentWebView();
        if (w != null) {
        	//通知内核当前的网络信息
            w.setNetworkType(type, subtype);
        }
    }

}

至此浏览器的分析基本上就结束了, 当然也不是特别全面, 回头看去, 也积累了很多东西, 多看代码, 每天积累一些, 对发展是又好处的.


Android Jetpack 全面学习 | WorkManager 入门

Android Jetpack 全面学习 | WorkManager 入门

WorkManager 提供了任务调度功能,我们可以对工作进行标记或命名。

1. 入门示例

gradle 引入依赖

将以下依赖项添加到应用模块的 build.gradle 文件中

dependencies {
    def work_version = "2.5.0"

    // (Java only)
    implementation "androidx.work:work-runtime:$work_version"

    // Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"

    // optional - RxJava2 support
    implementation "androidx.work:work-rxjava2:$work_version"

    // optional - GCMNetworkManager support
    implementation "androidx.work:work-gcm:$work_version"

    // optional - Test helpers
    androidTestImplementation "androidx.work:work-testing:$work_version"

    // optional - Multiprocess support
    implementation "androidx.work:work-multiprocess:$work_version"
}

添加依赖项并同步 Gradle 后,下一步要定义一些工作。

2. 定义工作

这里的工作为方便测试进行了简化。实际项目中请改为具体的业务代码。 新建 UploadWorker 类继承 Worker 类。需要 2 个参数 context: Context, params: WorkerParameters。 在doWork() 方法中是我们的具体任务,在 WorkManager 提供的后台线程上异步运行。

class UploadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    override fun doWork(): Result {
        for (i in 1..3) {
            Log.d(TAG, "模拟执行任务 ${tags.first()} ${Thread.currentThread()}")
            Thread.sleep(100) // 模拟耗时
        }
        return Result.success()
    }
}

doWork() 方法中我们打印当前线程信息。后面看看线程运行情况。

任务执行完毕,doWork() 需要返回一个 Result

  • Result.success():工作成功完成
  • Result.failure():工作失败
  • Result.retry():工作失败,应根据其重试政策在其他时间尝试

3. 创建 WorkRequest

前面我们定义好了工作类 UploadWorkerWorkManager 可以调度工作,让工作运行起来。工作可以在某个时间段内定期运行,也可以只运行一次。 要运行工作,涉及到 WorkRequest 类和它的子类。

这里我们演示只运行1次的工作,使用 OneTimeWorkRequest。 创建 workA,作为一个Activity 里的变量。

private val mWorkA = OneTimeWorkRequest.Builder(UploadWorker::class.java)
        .addTag("workA").build()

创建 workB

val workB = OneTimeWorkRequest.Builder(UploadWorker::class.java)
        .addTag("workB").build()

4. 将 WorkRequest 提交给 WorkManager

使用 enqueue 方法将 WorkRequest 提交给 WorkManager。

获取 WorkManager 的实例用 WorkManager.getInstance(applicationContext) 方法。

mWorkA 是变量

WorkManager.getInstance(applicationContext).enqueue(mWorkA)
// ...

workB 是每次都新建一个对象,然后交给 WorkManager 去执行。

val workB = OneTimeWorkRequest.Builder(UploadWorker::class.java)
        .addTag("workB").build()
WorkManager.getInstance(applicationContext).enqueue(workB)

执行工作器的确切时间取决于 WorkRequest 中使用的约束和系统优化方式。 Google 官方设计过 WorkManager,能够在满足约束的情况下提供最佳行为。

5. 运行测试

按钮A触发 mWorkA,按钮 B 触发 workB。分别点击按钮A/B

模拟执行任务 workA Thread[pool-2-thread-3,5,main]
模拟执行任务 workA Thread[pool-2-thread-3,5,main]
模拟执行任务 workA Thread[pool-2-thread-3,5,main]
点击按钮B Thread[main,5,main]
模拟执行任务 workB Thread[pool-2-thread-1,5,main]
模拟执行任务 workB Thread[pool-2-thread-1,5,main]
模拟执行任务 workB Thread[pool-2-thread-1,5,main]

观察 log 发现,工作的 doWork() 方法在 WorkManager 提供的后台线程上异步运行。 主线程是 [main,5,main],工作的线程是 [pool-2-thread-3,5,main]

而在实际操作中发现,多次点击按钮 A,mWorkA 只会执行第一次。后面再点击按钮 A,mWorkA 也不会执行了。

Android Jetpack库重要组件WorkManager的使用

Android Jetpack库重要组件WorkManager的使用

前言

WorkManager是Jetpack很重要的一个组件; 本篇我们就先来讲讲它是如何使用的,在讲解之前我们先了解关于后台处理的一些痛点

后台处理指南

我们知道每个 Android 应用都有一个主线程,它负责处理界面(包括测量和绘制视图)、协调用户互动以及接收生命周期事件; 如果有太多工作在主线程中进行,则应用可能会挂起或运行速度变慢,从而导致用户体验不佳。任何长时间运行的计算和操作(例如解码位图、访问磁盘或执行网络请求)都应在单独的后台线程上完成

一般来说,任何所需时间超过几毫秒的任务都应该分派到后台线程; 在用户与应用积极互动时,可能需要执行几项这样的任务;即使在用户没有积极使用应用时,应用可能也需要运行一些任务(例如,定期与后端服务器同步或定期从应用内提取新内容)

后台处理面临的挑战

后台任务会使用设备的有限资源,例如 RAM 和电池电量; 如果处理不当,可能会导致用户体验不佳;为了最大限度地延长电池续航时间并强制推行良好的应用行为,Android 会在应用(或前台服务通知)对用户不可见时,限制后台工作;为此Google在不同平台上逐步的改进

Android 6.0(API 级别 23)引入了低电耗模式和应用待机模式

低电耗模式会在未插接设备的电源,在屏幕关闭的情况下,让设备在一段时间内保持不活动状态,那么设备就会进入低电耗模式; 在低电耗模式下,系统会尝试通过限制应用访问占用大量网络和 CPU 资源的服务来节省电量。它还会阻止应用访问网络,并延迟其作业、同步和标准闹钟

系统会定期退出低电耗模式一小段时间,让应用完成其延迟的活动; 在此维护期内,系统会运行所有待处理的同步、作业和闹钟,并允许应用访问网络。在每个维护期结束时,系统会再次进入低电耗模式,暂停网络访问并推迟作业、同步和闹钟

随着时间的推移,系统安排维护期的次数越来越少,这有助于在设备未连接至充电器的情况下长期处于不活动状态时降低耗电量; 一旦用户通过移动设备、打开屏幕或连接至充电器唤醒设备,系统就会立即退出低电耗模式,并且所有应用都会恢复正常活动

应用待机模式允许系统判定应用在用户未主动使用它时是否处于闲置状态; 当用户有一段时间未触摸应用时,系统便会作出此判定;当用户将设备插入电源时,系统会从待机状态释放应用,允许它们自由访问网络并执行任何待处理的作业和同步。如果设备长时间处于闲置状态,系统将允许闲置应用访问网络,频率大约每天一次

低电耗模式和应用待机模式管理在 Android 6.0 或更高版本上运行的所有应用的行为,无论它们是否专用于 API 级别 23

Android 7.0(API 级别 24)限制了隐式广播

引入了随时随地使用低电耗模式; 使得低电耗模式又前进了一步,随时随地可以省电;只要屏幕关闭了一段时间,且设备未插入电源,低电耗模式就会对应用使用熟悉的 CPU 和网络限制;这意味着用户即使将设备放入口袋里也可以省电

Android 8.0(API 级别 26)进一步限制后台行为

例如在后台获取位置信息和释放缓存的唤醒锁定

Android 9.0(API 级别 28)引入了应用待机存储分区

通过它,系统会根据应用使用模式动态确定应用资源请求的优先级; 应用待机存储分区有助于系统根据应用的使用时间新近度和使用频率对应用资源请求确定优先级

根据应用使用模式,每个应用都会被放置在五个优先级存储分区之一中; 系统会根据应用所在的存储分区限制每个应用可用的设备资源

  • Android 6.0(API 级别 23)引入了低电耗模式和应用待机模式

低电耗模式会在屏幕处于关闭状态且设备处于静止状态时限制应用行为; 应用待机模式会将未使用的应用置于一种特殊状态,进入这种状态后,应用的网络访问、作业和同步会受到限制

  • Android 7.0(API 级别 24)限制了隐式广播,并引入了随时随地使用低电耗模式
  • Android 8.0(API 级别 26)进一步限制了后台行为,例如在后台获取位置信息和释放缓存的唤醒锁定
  • Android 9(API 级别 28)引入了应用待机存储分区,通过它,系统会根据应用使用模式动态确定应用资源请求的优先级

如何选择合适的后台解决方案

下面有一张图完美的解答了这个问题

  • 从上图我们可以清晰的了解如何选择后台解决方案,如果是一个长时间的http下载的话就使用DownloadManager
  • 否则的话就看是不是一个可以延迟的任务,如果不可以就使用Foreground service
  • 如果是的话就看是不是可以由系统条件触发,如果是的话就使用WorkManager
  • 如果不是就看是不是需要在一个固定的时间执行这个任务,如果是的话就使用AlarmManager
  • 如果不是的话就使用WorkManager

WorkManager概述

  • 使用 WorkManager API 可以轻松地调度可延迟的工作以及预计即使您的设备或应用重启也会运行的工作,即使在应用退出或设备重启时仍应运行的可延迟异步任务
  • 最高向后兼容到 API 14
  • 在运行 API 23 及以上级别的设备上使用 JobScheduler
  • 在运行 API 14-22 的设备上结合使用 BroadcastReceiver 和 AlarmManager
  • 添加网络可用性或充电状态等工作约束
  • 调度一次性或周期性异步任务
  • 监控和管理计划任务
  • 将任务链接起来
  • 确保任务执行,即使应用或设备重启也同样执行任务
  • 遵循低电耗模式等省电功能

WorkManager使用

1 声明依赖项

dependencies {
  def work_version = "2.3.1"

    // (Java only)
    implementation "androidx.work:work-runtime:$work_version"

    // Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"

    // optional - RxJava2 support
    implementation "androidx.work:work-rxjava2:$work_version"

    // optional - GCMNetworkManager support
    implementation "androidx.work:work-gcm:$work_version"

    // optional - Test helpers
    androidTestImplementation "androidx.work:work-testing:$work_version"
}

2 自定义一个继承自Worker的类

重写doWork方法,或者使用协程的话,得继承自CoroutineWorker。doWork方法有一个返回值,来标记任务是否成功或者是否要retry; 返回值有三种,分别是Result.success(),Result.failure(),Result.retry()

执行成功返回Result.success() 执行失败返回Result.failure() 需要重新执行返回Result.retry()

override fun doWork(): Result {
    for (i in 1..3) {
        Thread.sleep(500)
        Log.i("aaa", "count: $i parameter: ${inputData.getString("parameter1")}")
    }
    return Result.success(Data.Builder().putString("result1", "value of result1").build())
}

3 选择worker执行的条件

//添加约束
val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .setRequiresBatteryNotLow(false)
                .setRequiresCharging(false)
                .setRequiresDeviceIdle(false)
                .setRequiresStorageNotLow(false)
                .build()
  //对一次性执行添加约束,如果返回faliure或者retry的话就在适当的约束条件下执行worker
  val request = OneTimeWorkRequestBuilder<CountWorker>()
                .setConstraints(constraints)
                .setInputData(Data.Builder().putString("parameter1", "value of parameter1").build())
                .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.HOURS)
                .build()
 WorkManager.getInstance(context).enqueue(request)
//或者定时每隔一个小时执行任务  
val periodicWorkRequest = PeriodicWorkRequest.Builder(AppsWorker::class.java,
                                    1, TimeUnit.HOURS)
                                     .setConstraints(constraints)
                                     .build();
 WorkManager.getInstance(context).enqueue(periodicWorkRequest)

需要注意的是类似于JobSceeduler,周期性执行的任务最少间隔时间不能小于15mins

4 下面贴出自定义worker类的全部源码

class CountWorker(context: Context, parameters: WorkerParameters)
    : Worker(context, parameters) {
    companion object {
        fun enqueue(context: ComponentActivity) {
            val constraints = Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED)
                    .setRequiresBatteryNotLow(false)
                    .setRequiresCharging(false)
                    .setRequiresDeviceIdle(false)
                    .setRequiresStorageNotLow(false)
                    .build()
            val request = OneTimeWorkRequestBuilder<CountWorker>()
            		//-----1-----添加约束
                    .setConstraints(constraints)
                    //-----2----- 传入执行worker需要的数据
                    .setInputData(Data.Builder().putString("parameter1", "value of parameter1").build())
                    //-----3-----设置避退策略
                    .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.HOURS)
                    .build()
             //-----4-----将任务添加到队列中
            //WorkManager.getInstance(context).enqueue(request)
            //或者采用uniqueName执行
        	WorkManager.getInstance(context).beginUniqueWork("uniqueName", ExistingWorkPolicy.REPLACE, request).enqueue()
            //-----5-----对任务加入监听
            WorkManager.getInstance(context).getWorkInfoByIdLiveData(request.id).observe(context, Observer {
            	//-----8----获取doWork中传入的参数
                Log.i("aaa", "workInfo ${it.outputData.getString("result1")} ${it.state}: ")
            })
            //或者采用tag的方式监听状态
            WorkManager.getInstance(context).getWorkInfosByTagLiveData("tagCountWorker").observe(context, Observer {
            Log.i("aaa", "workInfo tag-- ${it[0].outputData.getString("result1")} ${it[0].state}: ")
        	})
        	//或者采用uniqueName的形式监听任务执行的状态
        	WorkManager.getInstance(context).getWorkInfosForUniqueWorkLiveData("uniqueName").observe(context, Observer {
            Log.i("aaa", "workInfo uniqueName-- ${it[0].outputData.getString("result1")} ${it[0].state}: ")
       	 })
        }
    }
    override fun doWork(): Result {
        for (i in 1..3) {
            Thread.sleep(500)
            //-----6-----获取传入的参数
            Log.i("aaa", "count: $i parameter: ${inputData.getString("parameter1")}")
        }
       //-----7-----传入返回的参数
        return Result.success(Data.Builder().putString("result1", "value of result1").build())
    }
}
  • 为了测试方便,我把执行的代码写在了enqueue中了,在enqueue中,我们首先在注释1处添加了约束
  • 在注释2处添加了执行worker需要的参数。这个参数可以在doWork中获取到,如注释6处所示;传入的数据不能超过10kb
  • 注释3处我们设置了避退策略,如果我们的一次性任务返回了retry,这里就可以起作用了,避退策略有两种方式。一种是指数级的EXPONENTIAL,还有一种是线性的LINEAR
  • 然后注释4处将任务加入到队列中,这里仅仅是加入队列,并不能保证执行,因为WorkManager主要的定位就是针对可延迟的任务,它需要根据添加的约束和系统自身的情况来做出什么时间执行这个任务
  • 注释5处可以根据request的id获取到任务的执行状态,返回值是一个LiveData类型的,并将其加入到生命周期观察序列中;所以当任务的执行状态发生变化的时候就会在注释8处打印信息
  • 我们还可以在任务执行结束的时候传入需要返回的参数,但是只能在success和failure的时候传入,传入的数据可以再注释8处获取

5 执行任务的方式

如果我们想要以链式执行一系列任务,如图所示,我们可以使用:

 WorkManager.getInstance(context).beginWith(requestA).then(requestB).enqueue()

如果我们的任务A和任务B之间没有关系,需要在任务A和B都完成的情况下执行任务C的话,如图所示,这时候就可以这么调用:

WorkManager.getInstance(context).beginWith(listOf(requestA,requestB)).then(requestC).enqueue()

如果我们想要AB和CD并行的执行完,然后执行E的话,如图所示,可以采用:

val continuation1 = WorkManager.getInstance(context).beginWith(requestA).then(requestB)
val continuation2 = WorkManager.getInstance(context).beginWith(requestC).then(requestD)
WorkContinuation.combine(listOf(continuation1, continuation2)).then(requestE).enqueue()

需要注意的是任务一旦发起,任务是可以保证一定会被执行的,就算退出应用,甚至重启手机都阻止不了他;但可能由于添加了环境约束等原因会在不确定的时间执行罢了

6 取消任务的执行

//通过request.id取消任务
WorkManager.getInstance(context).cancelWorkById(request.id)
//通过request的tag取消任务
WorkManager.getInstance(context).cancelAllWorkByTag("tag")
//通过request的uniqueName取消任务
WorkManager.getInstance(context).cancelUniqueWork("uniqueName")
//取消所有的work任务
WorkManager.getInstance(context).cancelAllWork()

以上可以看到可以通过四种方式取消任务

到此这篇关于Android Jetpack库重要组件WorkManager的使用的文章就介绍到这了,更多相关Android Jetpack WorkManager内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

您可能感兴趣的文章:
  • Android开发Jetpack组件Room用例讲解
  • Android Jetpack中Room的使用
  • Android Jetpack库剖析之ViewModel组件篇
  • Android Jetpack库剖析之LiveData组件篇
  • Android Jetpack库剖析之Lifecycle组件篇
  • Android开发Jetpack组件DataBinding用例详解
  • Android开发Jetpack组件WorkManager用例详解
  • Android开发Jetpack组件Room使用讲解

Android Studio 对现代 WorkManager 的支持

Android Studio 对现代 WorkManager 的支持

在 上一篇文章 中,我们提到了现代 WorkManager API 对工具支持方面也进行了改进,本文我们将结合实际案例来看看具体有哪些改进。如果您更喜欢通过视频了解此内容,请 点击此处 查看。

从 Android Studio Arctic Fox 开始,您可以直接 在 Android Studio 内使用后台任务检查器检查和调试 Worker。

后台任务检查器是应用检查套件的一部分,它针对应用的几个方面提供更丰富详细的信息。为了充分利用检查器,您的应用需要使用 WorkManager 2.5 或更新的版本。

应用检查器启用方法

首次打开应用检查器的最快方法是: 连续按两下 "Shift" 键,然后在弹出对话框中输入 App Inspection 并按回车键确认。您也可以从菜单栏依次选择: View → Tool Window → App Inspection 来打开应用检查器面板。

△ 打开 App Inspection 面板

△ 打开 App Inspection 面板

示例演示

本次演示使用了 Android Studio Bumblebee 和 GitHub 上公开的 WorkManager 示例。

在 App Inspection 面板中切换到后台任务检查器 (Background Task Inspector) 标签,勾选应用中的 Filter,然后点击 Apply 按钮。可以看到在随着过滤的持续进行,每个 Worker 在其生命周期中的状态也在持续变化着。由于这些 Worker 按照顺序运行,所以 CleanupWorker 需要在下一个 Worker 开始之前完成。其他的所有 Worker 此时要么处于排队状态,要么处于阻塞状态。

△ 使用 WorkManagerSample 应用和应用检查器面板

△ 使用 WorkManagerSample 应用和应用检查器面板

现在 CleanupWorker 已经完成,队列中的其他 Worker 也将按照次序运行。

△ 使用应用检查器面板的图表视图

△ 使用应用检查器面板的图表视图

您也可以从类似图示的图像中查看整个接续队列的内容。请从中选择一个 Worker,切换到图表视图 (按钮为流程图样式)。对于更加复杂的队列来说,图表视图是一种高效且不可或缺的理解手段。从这两种视图中,您都可以直接点击任何 Worker 来获得更详尽的分析。

△ 后台任务的详细信息

△ 后台任务的详细信息

在顶部是一个基本的说明信息,包括可点击的类名和一个唯一 ID。

数据库检查器

△ 数据库检查器面板

△ 数据库检查器面板

前面的内容我们谈到,WorkManager 会将您的工作数据持久化,那么下面我们用数据库检查器 (Database Inspector) 进一步看看这是怎样实现的。您可以点击数据库检查器标签页,并在其中查找某项工作的唯一 ID。您会发现,有关该特定执行的各项信息都被保存下来了。

后台任务检查器

您还可以进一步查看某个特定的执行被安排到了哪一个队列中。和手动搜索调用信息相比,这种经过编组整理的方式能够明显提升分析效率。您可以看到特定 Worker 是否受到限制,以及更加详细的频率和执行状态信息。

WorkManager 可以使用其中一个 Worker 的输出数据,并将其传递到流水线下游的另一个 Worker 中。这一点您可以从任务详细信息的结果 (Results) 中看到。输出数据包含着每个 Worker 的唯一标识符,会按照队列顺序进行传递。

△ 演示 Worker 执行失败的场景

△ 演示 Worker 执行失败的场景

这里为您展示当工作链中的某个 Worker 执行失败时的场景。在工作的接续队列中插入了一个出错的 Worker,然后重启应用。可以看到,上一次运行的结果仍然在这里供您检查。这也进一步印证了刚才说到的工作数据持久化特性。这里启动并应用过滤器,选择 Worker 后再次点击图表视图,这样就能迅速定位工作开始出错的位置 (您可以留意这里的感叹号)。您可以从这里点击直接进入 Worker 视图,然后继续调试出错的会话。

了解更多

通过本文您已经对新的后台任务检查器做了简单了解。以上便是 WorkManager 相关全部内容,如需更多资源,请参阅:

  • 现代 WorkManager API 已发布
  • WorkManager 系列文章: 使用 Dagger 自定义 WorkManager
  • WorkManager 文档: 使用 WorkManager 调度任务
  • Codelab: 使用 WorkManager 处理后台任务
  • Codelab: WorkManager 进阶知识
  • WorkManager 示例代码

欢迎您 点击这里 向我们提交反馈,或分享您喜欢的内容、发现的问题。您的反馈对我们非常重要,感谢您的支持!

关于android – 使用NetworkStatsManager获取移动数据使用历史记录android获取网络数据的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于Android Browser学习十四 NetworkStateHandler网络状态监听和处理、Android Jetpack 全面学习 | WorkManager 入门、Android Jetpack库重要组件WorkManager的使用、Android Studio 对现代 WorkManager 的支持等相关知识的信息别忘了在本站进行查找喔。

本文标签: