作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
由于我需要在 WorkManager 中异步执行工作,我需要使用 ListenableWorker
,默认情况下在主 (UI) 线程上运行。由于这项工作可能是一个很长的处理任务,可能会卡住界面,我想在后台线程上执行它。在 Working with WorkManager (Android Dev Summit '18) video ,Google 工程师展示了如何手动配置 WorkManager 以在自定义 Executor
上运行作品,所以我听从了他的指导:
1) 在 AndroidManifest 中禁用默认的 WorkManager 初始化程序:
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="com.example.myapp.workmanager-init"
tools:node="remove" />
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Configuration configuration = new Configuration.Builder().setExecutor(Executors.newSingleThreadExecutor()).build();
WorkManager.initialize(this, configuration);
}
}
ListenableWorker
这是:
@NonNull
@Override
public ListenableFuture<Result> startWork() {
Log.d(TAG, "Work started.");
mFuture = ResolvableFuture.create();
Result result = doWork();
mFuture.set(result);
return mFuture;
}
private Result doWork() {
Log.d(TAG, "isMainThread? " + isMainThread());
mFusedLocationProviderClient.getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
if (location != null) {
// Since I still don't know how to communicate with the UI, I will just log the location
Log.d(TAG, "Last location: " + location);
return Result.success();
} else {
return Result.failure();
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
e.printStackTrace();
return Result.failure();
}
});
}
private boolean isMainThread() {
return Looper.getMainLooper().getThread() == Thread.currentThread();
}
isMainThread()
即使我指定了
Executor
,方法也返回 true WorkManager 应该用作新的后台线程,我如何才能在后台线程上实际运行该工作?
ListenableWorker
需要
CountDownLatch
.
PeriodicWorkRequest
的最小间隔为 15 分钟的解决方法),我需要在前一项工作返回成功后执行此操作,否则我的行为会很奇怪。这是必需的,因为很明显,
ExistingWorkPolicy.APPEND
没有按预期工作。
public class LocationWorker extends ListenableWorker {
static final String UNIQUE_WORK_NAME = "LocationWorker";
static final String KEY_NEW_LOCATION = "new_location";
private static final String TAG = "LocationWorker";
private ResolvableFuture<Result> mFuture;
private LocationCallback mLocationCallback;
private CountDownLatch mLatch;
private Context mContext;
public LocationWorker(@NonNull final Context appContext, @NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
mContext = appContext;
Utils.setRequestingLocationUpdates(mContext, true);
mLatch = new CountDownLatch(1);
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
LocationUtils.getInstance(mContext).removeLocationUpdates(this);
Location location = locationResult.getLastLocation();
Log.d(TAG, "Work " + getId() + " returned: " + location);
mFuture.set(Result.success(Utils.getOutputData(location)));
// Rescheduling work
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(LocationWorker.class).setInitialDelay(10, TimeUnit.SECONDS).build();
WorkManager.getInstance().enqueueUniqueWork(LocationWorker.UNIQUE_WORK_NAME, ExistingWorkPolicy.KEEP, request);
Log.d(TAG, "Rescheduling work. New ID: " + request.getId());
// Relase lock
mLatch.countDown();
}
};
}
@NonNull
@Override
public ListenableFuture<Result> startWork() {
Log.d(TAG, "Starting work " + getId());
mFuture = ResolvableFuture.create();
LocationUtils.getInstance(mContext).requestSingleUpdate(mLocationCallback, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
LocationUtils.getInstance(mContext).removeLocationUpdates(mLocationCallback);
Utils.setRequestingLocationUpdates(mContext, false);
WorkManager.getInstance().cancelUniqueWork(UNIQUE_WORK_NAME);
mFuture.set(Result.failure());
// Relase lock
mLatch.countDown();
}
});
try {
mLatch.await(5L, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
return mFuture;
}
}
最佳答案
如果您想连续(即少于每 60 秒),您 绝对应该使用 foreground service和 不是 WorkManager,用于根据 the documentation :
deferrable, asynchronous tasks
doWork
方法在主线程上运行,因为根据
setExecutor() documentation :
An Executor for running Workers
ListenableWorker
的子类在
Executor
提供的后台线程上运行-
不是 您的
ListenableWorker
执行。
This method is called on the main thread.
ListenableWorker
, 你的
startWork
正如预期的那样,正在主线程上调用方法。既然你自己打电话
doWork()
方法在同一个线程上,你仍然会在主线程上。
Executor
因为你调用什么线程并不重要
getLastLocation()
上。
set
在您的
ResolvableFuture
上当您实际得到结果时 - 即在
onSuccess()
中或
onFailure
回调。这是给
WorkManager
的信号你实际上已经完成了你的工作:
public class LocationWorker extends ListenableWorker {
static final String UNIQUE_WORK_NAME = "LocationWorker";
static final String KEY_NEW_LOCATION = "new_location";
private static final String TAG = "LocationWorker";
private ResolvableFuture<Result> mFuture;
private LocationCallback mLocationCallback;
public LocationWorker(@NonNull final Context appContext, @NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
}
@NonNull
@Override
public ListenableFuture<Result> startWork() {
Log.d(TAG, "Starting work " + getId());
mFuture = ResolvableFuture.create();
Utils.setRequestingLocationUpdates(getApplicationContext(), true);
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
LocationUtils.getInstance(getApplicationContext()).removeLocationUpdates(this);
Location location = locationResult.getLastLocation();
Log.d(TAG, "Work " + getId() + " returned: " + location);
// Rescheduling work
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(LocationWorker.class).setInitialDelay(10, TimeUnit.SECONDS).build();
WorkManager.getInstance().enqueueUniqueWork(LocationWorker.UNIQUE_WORK_NAME, ExistingWorkPolicy.KEEP, request);
Log.d(TAG, "Rescheduling work. New ID: " + request.getId());
// Always set the result as the last operation
mFuture.set(Result.success(Utils.getOutputData(location)));
}
};
LocationUtils.getInstance(getApplicationContext()).requestSingleUpdate(mLocationCallback, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
LocationUtils.getInstance(getApplicationContext()).removeLocationUpdates(mLocationCallback);
Utils.setRequestingLocationUpdates(getApplicationContext(), false);
WorkManager.getInstance().cancelUniqueWork(UNIQUE_WORK_NAME);
mFuture.set(Result.failure());
}
});
return mFuture;
}
}
关于android - 如何在后台线程上运行 ListenableWorker 工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54083654/
我是一名优秀的程序员,十分优秀!