I am using RoboSpice for Rest Api calls in android and i want to add connection timeout for 30 secs in calls how i will do ?
here is my code
public class AddBrandsService extends
SpringAndroidSpiceRequest<AddBrands.Response> {
public final AddBrands.Response loadDataFromNetwork(){
return getRestTemplate().postForObject(url,
request, AddBrands.Response.class);
}
}
this service is called here
private SpiceManager contentManager = new SpiceManager(
JacksonSpringAndroidSpiceService.class);
contentManager.execute(service, lastRequestCacheKey,
DurationInMillis.ONE_SECOND, new AddBrandsListner());
thanks in advance...
Here is the code. Basically, you have to take care of the version of android as spring android switch between two different implementations to avoid a known bug in network stack. Unfortunately both implementations don't share a common interface whith respect to timeouts.
private void manageTimeOuts(RestTemplate restTemplate) {
// set timeout for requests
ClientHttpRequestFactory factory = restTemplate.getRequestFactory();
if (factory instanceof HttpComponentsClientHttpRequestFactory) {
HttpComponentsClientHttpRequestFactory advancedFactory = (HttpComponentsClientHttpRequestFactory) factory;
advancedFactory.setConnectTimeout(WEBSERVICES_TIMEOUT);
advancedFactory.setReadTimeout(WEBSERVICES_TIMEOUT);
} else if (factory instanceof SimpleClientHttpRequestFactory) {
SimpleClientHttpRequestFactory advancedFactory = (SimpleClientHttpRequestFactory) factory;
advancedFactory.setConnectTimeout(WEBSERVICES_TIMEOUT);
advancedFactory.setReadTimeout(WEBSERVICES_TIMEOUT);
}
}
Related
I have went through this and this post. So I really agree with the second post that presenter should not be aware of android specific thing. So what I am thinking is putting internet check in service layer.
I am using Rx Java for making network calls, so I can either place the network check before making a service call, so this way I need to manually throw and IOException because I need to show an error page on view when network is not available, the other option is I create my own error class for no internet
Observable<PaginationResponse<Notification>> response = Observable.create(new Observable.OnSubscribe<PaginationResponse<Notification>>() {
#Override
public void call(Subscriber<? super PaginationResponse<Notification>> subscriber) {
if (isNetworkConnected()) {
Call<List<Notification>> call = mService.getNotifications();
try {
Response<List<Notification>> response = call.execute();
processPaginationResponse(subscriber, response);
} catch (IOException e) {
e.printStackTrace();
subscriber.onError(e);
}
} else {
//This is I am adding manually
subscriber.onError(new IOException);
}
subscriber.onCompleted();
}
});
The other way I though of is adding interceptor to OkHttpClient and set it to retrofit
OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
builder.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
if (!isNetworkConnected()) {
throw new IOException();
}
final Request.Builder builder = chain.request().newBuilder();
Request request = builder.build();
return chain.proceed(request);
}
});
Now the 2nd approach is more scalable, but I am not sure it will be efficient as I would be unnecessarily calling service method and call.execute() method.
Any suggestion which way should be used?
Also my parameter for judging the way is
Efficiency
Scalability
Generic : I want this same logic can be used across apps who are following the similar architecture where MVP and Repository/DataProvider (May give data from network/db)
Other suggestions are also welcome, if you people are already using any other way.
First we create a utility for checking internet connection, there are two ways we can create this utility, one where the utility emits the status only once, which looks like this,
public class InternetConnection {
public static Observable<Boolean> isInternetOn(Context context) {
ConnectivityManager connectivityManager
= (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return Observable.just(activeNetworkInfo != null && activeNetworkInfo.isConnected());
}
}
Other way of creating this utility is, where the utility keeps emitting the connection status if it changes, which looks like this,
public class InternetConnection {
public Observable<Boolean> isInternetOn(Context context) {
final IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
return Observable.create(new Observable.OnSubscribe<Boolean>() {
#Override
public void call(final Subscriber<? super Boolean> subscriber) {
final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
subscriber.onNext(netInfo != null && netInfo.isConnected());
}
};
context.registerReceiver(receiver, filter);
subscriber.add(unsubscribeInUiThread(() -> context.unregisterReceiver(receiver)));
}
}).defaultIfEmpty(false);
}
private Subscription unsubscribeInUiThread(final Action0 unsubscribe) {
return Subscriptions.create(() -> {
if (Looper.getMainLooper() == Looper.myLooper()) {
unsubscribe.call();
} else {
final Scheduler.Worker inner = AndroidSchedulers.mainThread().createWorker();
inner.schedule(() -> {
unsubscribe.call();
inner.unsubscribe();
});
}
});
}
}
Next, in your dataSource or Presenter use switchMap or flatMap to check for internet connection before doing any network operation which looks like this,
private Observable<List<GitHubUser>> getGitHubUsersFromRetrofit() {
return isInternetOn(context)
.filter(connectionStatus -> connectionStatus)
.switchMap(connectionStatus -> gitHubApiInterface.getGitHubUsersList()
.map(gitHubUserList -> {
gitHubUserDao.storeOrUpdateGitHubUserList(gitHubUserList);
return gitHubUserList;
}));
}
Note that, we are using switchMap instead of flatMap. why switchMap? because, we have 2 data stream here, first is internet connection and second is Retrofit. first we will take connection status value (true/false), if we have active connection, we will create a new Retrofit stream and return start getting results, down the line if we the status of the connection changes, switchMap will first stop the existing Retrofit connection and then decide if we need to start a new one or ignore it.
EDIT:
This is one of the sample, which might give better clarity https://github.com/viraj49/Realm_android-injection-rx-test/blob/master/app-safeIntegration/src/main/java/tank/viraj/realm/dataSource/GitHubUserListDataSource.java
EDIT2:
So you mean switch map will try it itself once internet is back?
Yes and No, let's first see the difference between flatMap & switchMap. Let's say we have an editText and we search some info from network based on what user types, every time user adds a new character we have to make a new query (which can be reduced with debounce), now with so many network calls only the latest results are useful, with flatMap we will receive all the results from all the calls we made to the network, with switchMap on the other hand, the moment we make a query, all previous calls are discarded.
Now the solution here is made of 2 parts,
We need an Observable that keeps emitting current state of Network, the first InternetConnection above sends the status once and calls onComplete(), but the second one has a Broadcast receiver and it will keep sending onNext() when network status changes. IF you need to make a reactive solution go for case-2
Let's say you choose InternetConnection case-2, in this case use switchMap(), cause when network status changes, we need to stop Retrofit from whatever it is doing and then based on the status of network either make a new call or don't make a call.
How do I let my view know that the error is internet one also will this be scalable because I need to do with every network call, any suggestions regarding writing a wrapper?
Writing a wrapper would be excellent choice, you can create your own custom response which can take multiple entries from a set of possible responses e.g. SUCCESS_INTERNET, SUCCESS_LOGIN, ERROR_INVALID_ID
EDIT3: Please find an updated InternetConnectionUtil here https://github.com/viraj49/Realm_android-injection-rx-test/blob/master/app-safeIntegration/src/main/java/tank/viraj/realm/util/InternetConnection.java
More detail on the same topic is here: https://medium.com/#Viraj.Tank/android-mvp-that-survives-view-life-cycle-configuration-internet-changes-part-2-6b1e2b5c5294
EDIT4: I have recently created an Internet utility using Android Architecture Components - LiveData, you can find full source code here,
https://github.com/viraj49/Internet-Utitliy-using-AAC-LiveData
A detailed description of the code is here,
https://medium.com/#Viraj.Tank/internet-utility-using-android-architecture-components-livedata-e828a0fcd3db
I am trying to integrate Unit test cases for every chunk of code possible.
But I am facing issues while adding test cases for api calls that are made through retrofit.
The JUnit compiler never executes the code in the CallBack functions.
There is another option of making all the api calls Synchronous for testing purpose, but that's not possible for every case in my app.
How can I sort this out? I have to add test cases in the api calls by any means.
If you use .execute() instead of .enqueue() it makes execution synchron, thus the tests can ran properly without the need of importing 3 different libraries and adding any code or modify the build variants.
Like:
public class LoginAPITest {
#Test
public void login_Success() {
APIEndpoints apiEndpoints = RetrofitHelper.getTesterInstance().create(APIEndpoints.class);
Call<AuthResponse> call = apiEndpoints.postLogin();
try {
//Magic is here at .execute() instead of .enqueue()
Response<AuthResponse> response = call.execute();
AuthResponse authResponse = response.body();
assertTrue(response.isSuccessful() && authResponse.getBearer().startsWith("TestBearer"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
I test my Retrofit callbacks using Mockito, Robolectric and Hamcrest libraries.
First of all, set up lib stack in your module's build.gradle:
dependencies {
testCompile 'org.robolectric:robolectric:3.0'
testCompile "org.mockito:mockito-core:1.10.19"
androidTestCompile 'org.hamcrest:hamcrest-library:1.1'
}
In jour project's global build.gradle add following line to buildscript dependencies:
classpath 'org.robolectric:robolectric-gradle-plugin:1.0.1'
Then enter "Build Variants" menu in Android Studio (to quickly find it, hit Ctrl+Shift+A and search for it), and switch "Test Artifact" option to "Unit Tests". Android studio will switch your test folder to "com.your.package (test)" (instead of androidTest).
Ok. Set-up is done, time to write some tests!
Let's say you've got some retrofit api calls to retrieve a list of objects that need to be put into some adapter for a RecyclerView etc. We would like to test whether adapter gets filled with proper items on successful call.
To do this, we'll need to switch your Retrofit interface implementation, that you use to make calls with a mock, and do some fake responses taking advantage of Mockito ArgumentCaptor class.
#Config(constants = BuildConfig.class, sdk = 21,
manifest = "app/src/main/AndroidManifest.xml")
#RunWith(RobolectricGradleTestRunner.class)
public class RetrofitCallTest {
private MainActivity mainActivity;
#Mock
private RetrofitApi mockRetrofitApiImpl;
#Captor
private ArgumentCaptor<Callback<List<YourObject>>> callbackArgumentCaptor;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ActivityController<MainActivity> controller = Robolectric.buildActivity(MainActivity.class);
mainActivity = controller.get();
// Then we need to swap the retrofit api impl. with a mock one
// I usually store my Retrofit api impl as a static singleton in class RestClient, hence:
RestClient.setApi(mockRetrofitApiImpl);
controller.create();
}
#Test
public void shouldFillAdapter() throws Exception {
Mockito.verify(mockRetrofitApiImpl)
.getYourObject(callbackArgumentCaptor.capture());
int objectsQuantity = 10;
List<YourObject> list = new ArrayList<YourObject>();
for(int i = 0; i < objectsQuantity; ++i) {
list.add(new YourObject());
}
callbackArgumentCaptor.getValue().success(list, null);
YourAdapter yourAdapter = mainActivity.getAdapter(); // Obtain adapter
// Simple test check if adapter has as many items as put into response
assertThat(yourAdapter.getItemCount(), equalTo(objectsQuantity));
}
}
Proceed with the test by right clicking the test class and hitting run.
And that's it. I strongly suggest using Robolectric (with robolectric gradle plugin) and Mockito, these libs make testing android apps whole lotta easier.
I've learned this method from the following blog post. Also, refer to this answer.
Update: If you're using Retrofit with RxJava, check out my other answer on that too.
The JUnit framework never executes the code in the CallBack functions because the main thread of execution terminates before the response is retrieved. You can use CountDownLatch as shown below:
#Test
public void testApiResponse() {
CountDownLatch latch = new CountDownLatch(1);
mApiHelper.loadDataFromBackend(new Callback() {
#Override
public void onResponse(Call call, Response response) {
System.out.println("Success");
latch.countDown();
}
#Override
public void onFailure(Call call, Throwable t) {
System.out.println("Failure");
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
This test sample may be helpful too.
My advice isn't to perform testing for the API responses in the android app. There are many external tools for this.
Junit will not wait for async tasks to complete. You can use CountDownLatch (elegant solution which does NOT require an external library) to block the thread, until you receive response from server or timeout.
You can use CountDownLatch.
The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately.
//Step 1: Do your background job
latch.countDown(); //Step 2 : On completion ; notify the count down latch that your async task is done
latch.await(); // Step 3: keep waiting
OR you can specify a timeout in your await call
try {
latch.await(2000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
Sample Test Case
void testBackgroundJob() {
Latch latch = new CountDownLatch(1);
//Do your async job
Service.doSomething(new Callback() {
#Override
public void onResponse(){
ACTUAL_RESULT = SUCCESS;
latch.countDown(); // notify the count down latch
// assertEquals(..
}
});
//Wait for api response async
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
assertEquals(expectedResult, ACTUAL_RESULT);
}
if already encapsulation retrofit2.0 with rx with restful
open class BaseEntity<E> : Serializable {
/*result code*/
var status: Int = 0
/**data */
var content: E? = null
}
and server api request like
#GET(api/url)
fun getData():Observable<BaseEntity<Bean>>
your service call back just one sync request Observable
val it = service.getData().blockingSingle()
assertTrue(it.status == SUCCESS_CODE)
As #Islam Salah said:
The JUnit framework never executes the code in the CallBack functions because the main thread of execution terminates before the response is retrieved.
You can use awaitility to solve the problem. Check out this answer on StackOverflow.
I have an application that access to a server. When I quit the application, I have to disconnect from the server first, then close the application.
I would like to know if it's possible (and how) to make a Robospice service (background task) that disconnect from the server even if the application is closed (and the Robospice service is still running to finish the deconnection, and then auto kill itself after).
The problem is that the deconnection is too long (sometimes more than 5 secondes) and I would like to avoid blocking the phone during the deconnection, and allow the user to use it's phone.
Another question : is the Robospice librairy will be maintained and improved in the future (if necessary) ?
Yes, RoboSpice works just as well when attached to a Service Context as it works with an Activity one.
But you should probably try executing disconnect in the com.octo.android.robospice.SpiceService#onDestroy method of your implementation. This service is stopped whenever it has no meaningful work to do, so I guess it is the most appropriate solution for your use case.
I've solved my problem (that may be wasn't really a problem !) by ending my application with finish()
In my MainActivity, I use a Robospice service :
private final class LogoutListener implements PendingRequestListener<String> {
#Override
public void onRequestFailure(SpiceException spiceException) {
Log.e(TAG, spiceException.getMessage());
}
#Override
public void onRequestSuccess(String result) {
// nothing special
}
#Override
public void onRequestNotFound() {
Log.w(TAG, "Not found");
}
}
private void Alarm_Logout(boolean exit) {
Logout request = new Logout(url);
spiceManager.execute(request, new LogoutListener());
this.finish();
}
And the Lougout class :
public class Logout extends OkHttpSpiceRequest<String> {
private String url_logout;
public Logout(String url) {
super(String.class);
this.url_logout = url;
}
#Override
public String loadDataFromNetwork() throws Exception {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url_logout)
.build();
Response response = client.newCall(request).execute();
return "ok";
}
}
Before I closed the app with System.exit(0) in onRequestSuccess, so I had to wait the Logout complete. Now the app close (with finish()), but the Logout continue in background, and then, when done, the service finish...
In my android app, after sometime (hour or so.. not something determined) the connection and response to Google-AppEngine takes very long, something like 10 seconds or more.
After the first connection all other enpoint requests are done pretty quickly and this is why I believe this is SW issue and not internet connection issue.
Should I establish a 'dummy' connection as the app is loaded ?
Here is a sample code of an AsyncTask which tried to get User entity from AppEngine endpoint :
private class getUser extends AsyncTask<Void, Void, Boolean> {
long mTaskUserId = Constants.USER_ID_NO_ID_INFDICATOR;
String mIdInPlatform = Constants.USER_ID_NO_ID_INFDICATOR.toString();
Long mServerScore;
Context mContext;
String mUserName;
getUser(String idInPlatform, String userName, Context c) {
mIdInPlatform = idInPlatform;
mUserName = userName;
mContext = c;
}
#Override
protected Boolean doInBackground(Void... params) {
Userendpoint.Builder builder = new Userendpoint.Builder(
AndroidHttp.newCompatibleTransport(), new JacksonFactory(), null);
builder = CloudEndpointUtils.updateBuilder(builder);
Userendpoint endpoint = builder.build();
try {
User user = endpoint.getUser().execute();
} catch (IOException e) {
Log.e(TAG, "Error getting user details from server ", e);
return false;
}
this.mUserName = user.getUserName();
this.mServerScore = user.getScore();
this.mTaskUserId = user.getId();
return true;
}
#Override
protected void onPostExecute(Boolean result) {
if (result) {
setUserFacebookIdInPreferences(mIdInPlatform, mContext);
setUserIdInPreferences(this.mTaskUserId, mContext);
setScoreInPreferences(this.mServerScore, mContext);
setUserNameInPreferences(this.mUserName, mContext);
} else {
Toast.makeText(mContext, R.string.string_login_failed, Toast.LENGTH_SHORT).show();
}
// Restart login activity.
moveToLoginActivity(result);
super.onPostExecute(result);
}
}
Your application in Google App Engine uses two types of server instances: Dynamic instances and Resident instances. The difference is that dynamic instances are created in demand to serve traffic requests. Resident instances are always on.
When traffic stops, all your dynamic instances will shut down to save resources (and help you save money). The first time a request hits the server, a new dynamic instance will spin off to serve that request. The process of starting a new instance might take some time.
This is very likely what you are seeing in your application. To avoid that initial latency you can do two different things:
1) Optimize the time it takes for your code to load up.
2) Set up a Resident instance.
You can find more information on the Google documentation here:
https://developers.google.com/appengine/docs/adminconsole/instances#Introduction_to_Instances
You can warm-up your instances so that they're live before any query hits them - saving you this 10s delay. See documentation at:
https://developers.google.com/appengine/docs/adminconsole/instances#Warmup_Requests
Im very new to Google App Engine development. When integrating GAE with android, is it a good practice to place the code that initializes the endpoints in the Application class ? Meaning, initialize the endpoints once when the app is starting and then refer to those endpoints instances when doing some action with the backend ? My current practice is to create an endpoint instance each time i want to call the backend, but i feel its a little bit heavy and maybe unnecessary.
By "initializing the endpoints" i mean the following code :
Myendpoint.Builder endpointBuilder = new Myendpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(),
new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) { }
});
Myendpoint endpoint = CloudEndpointUtils.updateBuilder(endpointBuilder).build();
I usually create method that creates/gets it if created:
public YourEndpoint getEndpoint() {
if (endpoint == null) { // initialize .... };
return endpoint;
}
then have a resetEndpoint() that sets it back to null if you use cookies and you just wanna drop that session.