My app is using long polling to keep some local state up to date, but it also needs to communicate with the server while independently/simultaneously maintaining the long-polling connection.
The trouble is, OkHttp blocks any other calls to the server while it waits for the long-polling connection to receive data or timeout.
I've set up two OkHttpClient instances, one for normal API calls to the server, and the other to maintain the long-polling connection.
private static OkHttpClient client = new OkHttpClient();
private static OkHttpClient longPollingClient = new OkHttpClient();
I've tried having the long polling client set its own connection pool (separate from the default, shared connection pool )
ConnectionPool connectionPool = new ConnectionPool(
LONG_POLL_CLIENT_CONNECTION_POOL_MAX_CONNECTIONS, // 5
LONG_POLL_CLIENT_CONNECTION_POOL_KEEP_ALIVE_DURATION_MILLIS // 5 mins
);
longPollingClient.setConnectionPool(connectionPool);
I've also futzed with its dispatcher:
longPollingClient.getDispatcher().setMaxRequests(5);
longPollingClient.getDispatcher().setMaxRequestsPerHost(5);
But no matter what, calls on the vanilla client are blocked by the longPollingClient
Note, I'm using separate AsyncTasks for my calls. Does AsyncTask share a single thread in a thread pool? I'm relatively new to Android, so I'm not certain.
Related
I have a case where some users end up in a loop of requesting #GET API call too often.
Too often = 10-20x every second.
Currently, I've not located the problem and it seems that it's not going to be an easy fix, but I was wondering, is there a possibility to set some kind of limitations on Retrofit2, where if the app goes into some kind of loop where single API request is called so many times, it actually ignores these requests, for instance, do 1-5x same requests in a second max. or something similar?
How could this be done (from a networking library settings perspective)? (Till I find the root cause, I'd like to protect backend)
According the this answer you can use dispatcher as below:
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(1);
OkHttpClient client = new OkHttpClient.Builder()
.dispatcher(dispatcher)
.build()
After then you will be able to send one request on a time.
I've noticed from profiling that when my OkHttpClient is being created by the builder, TrustManagerFactory.getTrustManagers seems to be taking a long time and is blocking my UI thread on startup. It takes about 111 millis to complete.
Not being extremely familiar with TrustManagers, I was wondering if there might be a faster method that's still secure to provide these to the OkHttpClient, and remove this as a concern.
In the mean time, I'll see if I can't defer the creation of my OkHttpClient to a background thread.
You should be able to call
OkHttpClient client = new OkHttpClient.Builder().sslSocketFactory(sslSocketFactory, trustManager).build();
https://github.com/square/okhttp/blob/4568075b1a163bec48a8598917e6d6bcc9b2d96b/okhttp/src/main/java/okhttp3/OkHttpClient.java#L655
But ultimately this is doing what you will need to do, triggering the JVM to load loading SSL related classes, load CA certificates from the system etc. So it seems unlikely this is a performance win.
Creating the OkHttpClient on a background thread sounds like the best option.
I have used retrofit creating new objects each time I use a webservice . The webservice response time is good . But when tried within the app it slows down.
Does this effect the response?
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ApiConstants.BASE_URL)
.addCallAdapterFactory(new ErrorCallback.ErrorHandlingCallAdapterFactory())
.addConverterFactory(GsonConverterFactory.create())
.build();
In the Retrofit documentation the build, baseUrl, addCallAdapterFactory, addConverterFactory operations dont entablish any connections. This make sense because they are used just to prepare the Retrofit instance for communication.
Also, considering that restful servicies typically use HTTP for communication, there is no need to entablish a connection per session. The connection entablishes every time you call an operation of the webservice api.
So, creating the instance everytime will no affect in terms of communication, but it will affect the client cpu and memory resources unnecessary.
Creating a new Retrofit instance does affect the response time and I can confirm this by my own recent experience. If I created new instance for each request the response time that I was getting was >= 1700ms where as when I used single instance for API calls, I got response in <= 500 ms.
I'm using OkHttp at the first time. I see the tutorial said that If wanna use Response Caching, I must call new OkHttpClient() exactly once (a singleton instance). OkhttpClient is thread-safe by synchronized methods. But in my application, there are many threads connects to the network to get remote data simultaneously, some threads must wait for a thread have done getting data to execute its operation.
So Is it's performance not better than normal?
If yes, If I don't enable Reponse Caching, should I call new OkHttpClient() many times for better performance?
Thanks
For the best performance, share a single OkHttpClient instance. This allows your cache to be shared, and in the future when we implement fancy joining & cancelling it’ll allow outgoing requests to be merged.
Is it ok to use the same HttpClient *object* for several execute method calls?
(assuming I'm not executing the HttpGet requests simultaneously)
You can use AndroidHttpClient to do that with api 8 or above. See this link to know how to work with AndroidHttpClient: http://www.java2s.com/Code/Android/Network/CreateHttpconnection.htm
Otherwise, you can use ThreadSafeClientConnManager. "This connection manager doesn’t handle a single connection, but a pool of them, where each connection can be taken from the pool, allocated to a thread (which then has exclusive access to it), and returned to the pool once the thread yields it. If the same or another thread claims a connection for the same route, then a connection can be immediately reused from the pool without the need to first close and reopen it, thereby avoiding the overhead of the handshake performed by HTTP when establishing a new connection.ThreadSafeClientConnManager for instance sets the default values for the maximum number of total connections to 20, and the maximum number of connections per route to 2."
- from "Android in Practice"
You can see this link to know about ThreadSafeClientConnManager: http://massapi.com/class/th/ThreadSafeClientConnManager.html
It's not safe to use same HttpClient, but you can use AndroidHttpClient,
AndroidHttpClient client = AndroidHttpClient.newInstance("xxxx");
AndroidHttpClient is thread safe.