Reputation: 43
I am using Work Manger to make a network call and fetch some data, for that I've used OneTimeRequest. The call responses perfectly inside the worker class but it returns blank result in the Life cycle Owner that is watching the work.
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);
For observing the response from the worker 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("")){
}
}
});
But the thing is, the response string is always blank!! Even if the work manager has completed the task and the network response is there in worker but when i use setOutputData it gives blank data.
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);
Worker 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;
}
}
Upvotes: 4
Views: 8779
Reputation: 1
==========================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();
}
}
Upvotes: 0
Reputation: 21134
You could also use something like this:
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;
}
The idea is to expose a synchronous API via Retrofit itself, or to use a CountDownLatch
. Bear in mind that you could be using an additional thread in your threadpool when you do something like this (as Retrofit could potentially use a different thread pool).
Upvotes: 5
Reputation: 5321
The problem is that you are returning Result.Success
before onResponse
is triggered as you are doing an async retrofit request, hence no data being set in worker status.
One of the many workaround is that you send an synchronous retrofit request within your worker, thus your doWork()
method will be blocked until you get a network response. You have to change your async retrofit request to synchronous, something like the following code snippet:
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;
}
}
Upvotes: 10