Android 工作经理一次请求 returns 工作人员的空白结果
Android Work Manager One time Request returns blank result from worker
我正在使用 Work Manger 进行网络调用并获取一些数据,为此我使用了 OneTimeRequest。调用在工作人员 class 内完美响应,但它 returns 空白导致正在监视工作的生命周期所有者。
workManager= WorkManager.getInstance();
OneTimeWorkRequest.Builder encryptionWork =new OneTimeWorkRequest.Builder(NetworkWorker.class);
getUsersWorkReq=encryptionWork.setInputData(getWorkerInput(EXPERT_LIST_REQUEST))
.addTag(Constant.WORK_GETUSER)
.build();
workManager.enqueue(getUsersWorkReq);
观察工作人员的反应class
workManager.getStatusById(getUsersWorkReq.getId()).observe(this, workStatus -> {
if (workStatus != null && workStatus.getState().isFinished()) {
String status=workStatus.getOutputData().getString(Constant.WORK_RESULT);
String response=workStatus.getOutputData().getString(Constant.WORK_RESPONSE);
if(status!=null && !status.equalsIgnoreCase("")){
}
}
});
但问题是,响应字符串始终为空!!即使工作经理已完成任务并且工作人员中有网络响应,但当我使用 setOutputData 时它会提供空白数据。
outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_SUCCESS)
.putString(Constant.WORK_RESPONSE, String.valueOf(response.body()))
.build();
Log.e("WORKER", "onResponse: "+ response.body().getMsg() );
setOutputData(outPut);
工人Class
public class NetworkWorker extends Worker {
Data outPut;
@NonNull
@Override
public Result doWork() {
ApiService service = RetrofitInstance.getRetrofitInstance().create(ApiService.class);
Call<ExpertListResponse> call = service.get_recommended_users();
Log.wtf("URL Called", call.request().url() + "");
call.enqueue(new Callback<ExpertListResponse>() {
@Override
public void onResponse(Call<ExpertListResponse> call, Response<ExpertListResponse> response) {
//onFinishedListener.onFinished(requestTag, response.body() != null ? response.body().getExpertInfo() : null);
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_SUCCESS)
.putString(Constant.WORK_RESPONSE, String.valueOf(response.code()))
.build();
Log.e("WORKER", "onResponse: "+ response.body().getMsg() );
setOutputData(outPut);
}
@Override
public void onFailure(Call<ExpertListResponse> call, Throwable t) {
//onFinishedListener.onFailure(requestTag,t);
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_FAILURE)
.putString(Constant.WORK_RESPONSE, String.valueOf(t))
.build();
setOutputData(outPut);
}
});
return Result.SUCCESS;
}
}
问题是您在触发 onResponse
之前返回 Result.Success
,因为您正在执行异步改造请求,因此没有数据被设置为工作状态。
众多解决方法之一是您在您的 worker 中发送同步改造请求,因此您的 doWork()
方法将被阻止,直到您获得网络响应。您必须将异步改装请求更改为同步,类似于以下代码片段:
public Result doWork() {
try {
ApiService service = RetrofitInstance.getRetrofitInstance()
.create(ApiService.class);
Call<ExpertListResponse> call = service.get_recommended_users();
ExpertListResponse response = call.execute().body();
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_SUCCESS)
.putString(Constant.WORK_RESPONSE, String.valueOf(response.code()))
.build();
setOutputData(outPut);
return Result.SUCCESS;
} catch(Exception ex){
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_FAILURE)
.putString(Constant.WORK_RESPONSE, String.valueOf(t))
.build();
setOutputData(outPut);
return Result.Failure;
}
}
你也可以这样使用:
public class NetworkWorker extends Worker {
private static final long MAX_WAIT_TIME_SECONDS = 10L;
Data outPut;
CountDownLatch latch;
@NonNull
@Override
public Result doWork() {
// Need to wait for the onResponse() call.
latch = new CountDownLatch(1);
ApiService service = RetrofitInstance.getRetrofitInstance().create(ApiService.class);
Call<ExpertListResponse> call = service.get_recommended_users();
call.enqueue(new Callback<ExpertListResponse>() {
@Override
public void onResponse(Call<ExpertListResponse> call, Response<ExpertListResponse> response) {
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_SUCCESS)
.putString(Constant.WORK_RESPONSE, String.valueOf(response.code()))
.build();
Log.e("WORKER", "onResponse: "+ response.body().getMsg() );
latch.countdown();
setOutputData(outPut);
}
@Override
public void onFailure(Call<ExpertListResponse> call, Throwable t) {
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_FAILURE)
.putString(Constant.WORK_RESPONSE, String.valueOf(t))
.build();
latch.countdown();
setOutputData(outPut);
}
});
latch.await(MAX_WAIT_TIME_SECONDS, TimeUnit.SECONDS);
return Result.SUCCESS;
}
想法是通过 Retrofit 本身公开同步 API,或者使用 CountDownLatch
。请记住,当您执行此类操作时,您可能会在线程池中使用额外的线程(因为 Retrofit 可能会使用不同的线程池)。
==========================Activity==========================
OneTimeWorkRequest movieOneTimeRequest;
WorkManager workManager;
private void callWorkerApiInBackground() {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
Data inputData = createInputData();
movieOneTimeRequest = new OneTimeWorkRequest.Builder(MovieWorker.class)
.setConstraints(constraints)
.setInputData(inputData)
.build();
workManager.getWorkInfoByIdLiveData(movieOneTimeRequest.getId()).observe(this, workInfo -> {
if (workInfo != null) {
Log.e(TAG, "WorkInfo received: state: " + workInfo.getState());
switch(workInfo.getState()){
case FAILED:
Log.e(TAG, "OBSERVING :: fail");
break;
case BLOCKED:
Log.e(TAG, "OBSERVING :: blocked");
break;
case RUNNING:
Log.e(TAG, "OBSERVING :: running");
break;
case ENQUEUED:
Log.e(TAG, "OBSERVING :: enqueued");
break;
case CANCELLED:
Log.e(TAG, "OBSERVING :: cancelled");
break;
case SUCCEEDED:
Log.e(TAG, "OBSERVING :: succeeded");
String workManagerOutput = workInfo.getOutputData().getString(MovieWorker.KEY_OUTPUT);
Log.e(TAG, " workManagerOutput: " + workManagerOutput);
break;
}
}
});
workManager.enqueue(movieOneTimeRequest);
}
private Data createInputData() {
Data.Builder builder = new Data.Builder();
String imageUrl = "www.image.come";
if (!TextUtils.isEmpty(imageUrl)) {
builder.putString(MovieWorker.KEY_IMAGE,imageUrl);
}
return builder.build();
}
=================================== MovieWorker ========= ==============
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import com.aiplocationtest.models.MovieData;
import com.aiplocationtest.network.NetworkApiClient;
import java.util.List;
public class MovieWorker extends Worker {
public static final String KEY_IMAGE = "image";
public static final String KEY_OUTPUT = "output";
String TAG = MovieWorker.class.getSimpleName();
String imageUrl;
public MovieWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
imageUrl = workerParams.getInputData().getString(KEY_IMAGE);
Log.e(TAG, " imageUrl : " + imageUrl);
}
@NonNull
@Override
public Result doWork() {
try {
List<MovieData> response = NetworkApiClient.getMovieList().execute().body();
Data outputData = new Data.Builder()
.putString(KEY_OUTPUT, response.toString())
.build();
return Result.success(outputData);
// return Result.success();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, " callMovieListApi Exception : " + e.getMessage());
return Result.failure();
}
}
}
======================NetworkApiClient ====================
import com.aiplocationtest.models.MovieData;
import java.util.List;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
public class NetworkApiClient {
public static Retrofit getRestAdapter() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
return new Retrofit.Builder()
.baseUrl(HttpConstant.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static Call<List<MovieData>> getMovieList() {
return getRestAdapter().create(GetAPi.class).getMovieList();
}
public interface GetAPi {
@GET(HttpConstant.MOVIE_LIST)
Call<List<MovieData>> getMovieList();
}
}
我正在使用 Work Manger 进行网络调用并获取一些数据,为此我使用了 OneTimeRequest。调用在工作人员 class 内完美响应,但它 returns 空白导致正在监视工作的生命周期所有者。
workManager= WorkManager.getInstance();
OneTimeWorkRequest.Builder encryptionWork =new OneTimeWorkRequest.Builder(NetworkWorker.class);
getUsersWorkReq=encryptionWork.setInputData(getWorkerInput(EXPERT_LIST_REQUEST))
.addTag(Constant.WORK_GETUSER)
.build();
workManager.enqueue(getUsersWorkReq);
观察工作人员的反应class
workManager.getStatusById(getUsersWorkReq.getId()).observe(this, workStatus -> {
if (workStatus != null && workStatus.getState().isFinished()) {
String status=workStatus.getOutputData().getString(Constant.WORK_RESULT);
String response=workStatus.getOutputData().getString(Constant.WORK_RESPONSE);
if(status!=null && !status.equalsIgnoreCase("")){
}
}
});
但问题是,响应字符串始终为空!!即使工作经理已完成任务并且工作人员中有网络响应,但当我使用 setOutputData 时它会提供空白数据。
outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_SUCCESS)
.putString(Constant.WORK_RESPONSE, String.valueOf(response.body()))
.build();
Log.e("WORKER", "onResponse: "+ response.body().getMsg() );
setOutputData(outPut);
工人Class
public class NetworkWorker extends Worker {
Data outPut;
@NonNull
@Override
public Result doWork() {
ApiService service = RetrofitInstance.getRetrofitInstance().create(ApiService.class);
Call<ExpertListResponse> call = service.get_recommended_users();
Log.wtf("URL Called", call.request().url() + "");
call.enqueue(new Callback<ExpertListResponse>() {
@Override
public void onResponse(Call<ExpertListResponse> call, Response<ExpertListResponse> response) {
//onFinishedListener.onFinished(requestTag, response.body() != null ? response.body().getExpertInfo() : null);
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_SUCCESS)
.putString(Constant.WORK_RESPONSE, String.valueOf(response.code()))
.build();
Log.e("WORKER", "onResponse: "+ response.body().getMsg() );
setOutputData(outPut);
}
@Override
public void onFailure(Call<ExpertListResponse> call, Throwable t) {
//onFinishedListener.onFailure(requestTag,t);
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_FAILURE)
.putString(Constant.WORK_RESPONSE, String.valueOf(t))
.build();
setOutputData(outPut);
}
});
return Result.SUCCESS;
}
}
问题是您在触发 onResponse
之前返回 Result.Success
,因为您正在执行异步改造请求,因此没有数据被设置为工作状态。
众多解决方法之一是您在您的 worker 中发送同步改造请求,因此您的 doWork()
方法将被阻止,直到您获得网络响应。您必须将异步改装请求更改为同步,类似于以下代码片段:
public Result doWork() {
try {
ApiService service = RetrofitInstance.getRetrofitInstance()
.create(ApiService.class);
Call<ExpertListResponse> call = service.get_recommended_users();
ExpertListResponse response = call.execute().body();
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_SUCCESS)
.putString(Constant.WORK_RESPONSE, String.valueOf(response.code()))
.build();
setOutputData(outPut);
return Result.SUCCESS;
} catch(Exception ex){
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_FAILURE)
.putString(Constant.WORK_RESPONSE, String.valueOf(t))
.build();
setOutputData(outPut);
return Result.Failure;
}
}
你也可以这样使用:
public class NetworkWorker extends Worker {
private static final long MAX_WAIT_TIME_SECONDS = 10L;
Data outPut;
CountDownLatch latch;
@NonNull
@Override
public Result doWork() {
// Need to wait for the onResponse() call.
latch = new CountDownLatch(1);
ApiService service = RetrofitInstance.getRetrofitInstance().create(ApiService.class);
Call<ExpertListResponse> call = service.get_recommended_users();
call.enqueue(new Callback<ExpertListResponse>() {
@Override
public void onResponse(Call<ExpertListResponse> call, Response<ExpertListResponse> response) {
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_SUCCESS)
.putString(Constant.WORK_RESPONSE, String.valueOf(response.code()))
.build();
Log.e("WORKER", "onResponse: "+ response.body().getMsg() );
latch.countdown();
setOutputData(outPut);
}
@Override
public void onFailure(Call<ExpertListResponse> call, Throwable t) {
Data outPut = new Data.Builder()
.putString(Constant.WORK_RESULT,Constant.WORK_FAILURE)
.putString(Constant.WORK_RESPONSE, String.valueOf(t))
.build();
latch.countdown();
setOutputData(outPut);
}
});
latch.await(MAX_WAIT_TIME_SECONDS, TimeUnit.SECONDS);
return Result.SUCCESS;
}
想法是通过 Retrofit 本身公开同步 API,或者使用 CountDownLatch
。请记住,当您执行此类操作时,您可能会在线程池中使用额外的线程(因为 Retrofit 可能会使用不同的线程池)。
==========================Activity==========================
OneTimeWorkRequest movieOneTimeRequest;
WorkManager workManager;
private void callWorkerApiInBackground() {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
Data inputData = createInputData();
movieOneTimeRequest = new OneTimeWorkRequest.Builder(MovieWorker.class)
.setConstraints(constraints)
.setInputData(inputData)
.build();
workManager.getWorkInfoByIdLiveData(movieOneTimeRequest.getId()).observe(this, workInfo -> {
if (workInfo != null) {
Log.e(TAG, "WorkInfo received: state: " + workInfo.getState());
switch(workInfo.getState()){
case FAILED:
Log.e(TAG, "OBSERVING :: fail");
break;
case BLOCKED:
Log.e(TAG, "OBSERVING :: blocked");
break;
case RUNNING:
Log.e(TAG, "OBSERVING :: running");
break;
case ENQUEUED:
Log.e(TAG, "OBSERVING :: enqueued");
break;
case CANCELLED:
Log.e(TAG, "OBSERVING :: cancelled");
break;
case SUCCEEDED:
Log.e(TAG, "OBSERVING :: succeeded");
String workManagerOutput = workInfo.getOutputData().getString(MovieWorker.KEY_OUTPUT);
Log.e(TAG, " workManagerOutput: " + workManagerOutput);
break;
}
}
});
workManager.enqueue(movieOneTimeRequest);
}
private Data createInputData() {
Data.Builder builder = new Data.Builder();
String imageUrl = "www.image.come";
if (!TextUtils.isEmpty(imageUrl)) {
builder.putString(MovieWorker.KEY_IMAGE,imageUrl);
}
return builder.build();
}
=================================== MovieWorker ========= ==============
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import com.aiplocationtest.models.MovieData;
import com.aiplocationtest.network.NetworkApiClient;
import java.util.List;
public class MovieWorker extends Worker {
public static final String KEY_IMAGE = "image";
public static final String KEY_OUTPUT = "output";
String TAG = MovieWorker.class.getSimpleName();
String imageUrl;
public MovieWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
imageUrl = workerParams.getInputData().getString(KEY_IMAGE);
Log.e(TAG, " imageUrl : " + imageUrl);
}
@NonNull
@Override
public Result doWork() {
try {
List<MovieData> response = NetworkApiClient.getMovieList().execute().body();
Data outputData = new Data.Builder()
.putString(KEY_OUTPUT, response.toString())
.build();
return Result.success(outputData);
// return Result.success();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, " callMovieListApi Exception : " + e.getMessage());
return Result.failure();
}
}
}
======================NetworkApiClient ====================
import com.aiplocationtest.models.MovieData;
import java.util.List;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
public class NetworkApiClient {
public static Retrofit getRestAdapter() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
return new Retrofit.Builder()
.baseUrl(HttpConstant.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static Call<List<MovieData>> getMovieList() {
return getRestAdapter().create(GetAPi.class).getMovieList();
}
public interface GetAPi {
@GET(HttpConstant.MOVIE_LIST)
Call<List<MovieData>> getMovieList();
}
}