Is WorkManager the right solution for me?

889 Views Asked by At

I have following requirement in my app. 1. I select some files & click Upload button. On clicking Upload button, the app exits. (I am enqueueing the request & finishing the activity). 2. Once the app exits, these files need to get synced to server in background. 3. Also after certain time duration (I have set 16min interval), in background, I need to check if there is unsynced data, sync it in background. 4. If user is offline, the unsynced data should get synced in background once network connectivity is established.

I have used WorkManager's Periodic Work Request to achieve this. But on testing it on my Asus Zenfone3, I observed that : 1. If my device goes into sleep mode, the doWork() does not get execute after that.

  1. If I turn off mobile data & then turn it on, the doWork() does not get executed immediately. I have set 1 constraint : .setRequiredNetworkType(NetworkType.CONNECTED). It gets executed only after its interval is completed. I need immediate sync on network.

  2. Also sometimes, clicking on upload button does not immd call doWork().

Is WorkManager (2.3.2) the right approach I am following. Any guideline to achieve above req. will be appreciated.

2

There are 2 best solutions below

0
On

WorkManager is the preferred solution on Android for deferrable tasks. If you want an immediate action, you may want to look into implementing the logic you want in a Foreground Service.

Regarding what happens when your device goes into doze mode, WorkManager tries to minimize battery consumption and respect it. Again, if you need to have your tasks to be executed even when the device is supposed to go into doze mode, WorkManager is not the right solution. But you need to have a good reason to justify this behavior as it is going to have a negative impact on battery life.

To be able to understand what is happening with the Asus Zenfone3, it would be helpful to see how you enqueue the WorkRequest and WorkManager's logs.

1
On

If you read android documentation work manager is not a good way to schedule recurring tasks and when the device goes to sleep mode the thread work manager is working on is also put to sleep to conserve battery try using handler instead. https://developer.android.com/reference/android/os/Handler in the code i have posted i have used handler and firebase jobdispatcher to log user location on fixed interval of 30 seconds and it works even when device is in sleep mode

//file with handler and firebase job dispatcher

public class GetterService extends JobService {
private HandlerThread handlerThread = new HandlerThread("HandlerThread");
private Handler threadHandler;
int delay = 30*1000;
Runnable runnable;
LocationManager locationManager;

@Override
public boolean onStartJob(@NonNull com.firebase.jobdispatcher.JobParameters job) {
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    handlerThread.start();
    threadHandler = new Handler();
    threadHandler.postDelayed(runnable= () -> {
        if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        Location repeatedLocations = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        Log.i("location logger", "getting Longitude as "+ repeatedLocations.getLongitude() +" getting Latitide as "+repeatedLocations.getLatitude());
        threadHandler.postDelayed(runnable,delay);
    },delay);
    return false;
}

@Override
public boolean onStopJob(@NonNull com.firebase.jobdispatcher.JobParameters job) {
    return false;
}

}

//file with location getter

public class LocationGetter extends AppCompatActivity implements LocationListener {
LocationManager locationManager;
@BindView(R.id.latitudeVal)
TextView latitudeVal;
@BindView(R.id.longitudeVal)
TextView longitudeVal;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 2);
    } else {
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 1, this);
    }
    FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher
            (new GooglePlayDriver(getApplicationContext()));

    Job notificationJob = dispatcher.newJobBuilder()
            .setService(GetterService.class)
            .setRecurring(true).setTag("jid")
            .setLifetime(Lifetime.UNTIL_NEXT_BOOT)
            .setTrigger(Trigger.executionWindow(1, 10000))
            .setReplaceCurrent(false)
            .build();
    dispatcher.mustSchedule(notificationJob);
}

@OnClick(R.id.ping)
public void onPingClick() {

}

@Override
public void onLocationChanged(Location location) {
    latitudeVal.setText("" + location.getLatitude() + "");
    longitudeVal.setText("" + location.getLongitude() + "");
    Log.i("dfjh", "" + location.getLongitude() + "    " + location.getLatitude());
}

@Override
public void onStatusChanged(String s, int i, Bundle bundle) {

}

@Override
public void onProviderEnabled(String s) {

}

@Override
public void onProviderDisabled(String s) {

}

@Override
protected void onDestroy() {
    super.onDestroy();

}

}