this is my first post on stackoverflow so I hope I am doing everything correctly. I am developing my first android App and I am experiencing weird behavior on some devices. I have a foreground service that periodically obtains the location of the device and I use a handler with a delayed runner to send it to a server. In my phone (Marshmallow, API 23) everything is working fine, but a friend who uses a Xiaomi phone running Lollipop (API 21) fails to connect to the server when the App's activities are in the background. This is the function that sends the location to the server:
private void sendLocation(final String request_id, final String location ) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RestServiceConstants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
String email = prefManager.pref.getString("UserEmail","");
String password = prefManager.pref.getString("UserPassword","");
Log.d(TAG,"sendLocation called");
RestService service = retrofit.create(RestService.class);
Call<StatusResponse> call = service.location("Basic "+ Base64.encodeToString((email + ":" + password).getBytes(),Base64.NO_WRAP),
request_id,location);
call.enqueue(new Callback<StatusResponse>() {
@Override
public void onResponse(Call<StatusResponse> call, Response<StatusResponse> response) {
Log.d(TAG, "onResponse: raw: " + response.body());
if (response.isSuccess() && response.body() != null){
Log.d(TAG, "The location has been sent successfully");
if(resendLocationHandler != null)
resendLocationHandler.removeCallbacksAndMessages(null);
} else if (response.code() == 401){
Log.i(TAG, "onCreate: User not logged in");
prefManager.setIsLoggedIn(false);
} else {
Log.i(TAG, "sendLocation Unknown error occurred");
}
}
@Override
public void onFailure(Call<StatusResponse> call, Throwable t) {
Log.i(TAG, "sendLocation Failed to get the server");
if(resendLocationHandler == null)
resendLocationHandler = new Handler();
resendLocationHandler.postDelayed(new Runnable() {
@Override
public void run() {
sendLocation(request_id, location);
}
}, resendFailedRequestDelay);
}
});
}
I don't know what else should I provide to help you diagnose the issue so feel free to request whatever may seem relevant. Thanks in advance
Edit: what I mean by the request failing is that it triggers the onFailure callback. The exception caught in the callback is:
java.net.ConnectException: Failed to connect to my_server_address:80
at okhttp3.internal.io.RealConnection.connectSocket(RealConnection.java:139)
at okhttp3.internal.io.RealConnection.connect(RealConnection.java:108)
at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:188)
at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:127)
at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:289)
at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
at okhttp3.RealCall.getResponse(RealCall.java:240)
at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:198)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:160)
at okhttp3.RealCall.access$100(RealCall.java:30)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:127)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:33)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Check following permission added in manifest file
It may be related some kind of "Battery optimization" which could prevent background apps from accessing the network -- see, for example, https://www.reddit.com/r/Xiaomi/comments/4r6eld/does_battery_optimization_ever_work_for/
So, it may be that Xiaomi users (and users whose devices have similar functionality) need to manually add your app to a whitelist.
I don't know if "optimization" settings like these are on by default -- I would certainly hope they aren't.