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.
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 been executing tasks like so:
LoginTask loginTask = new LoginTask(startActivityLayout, getApplicationContext(), usernameEdit, passwordEdit, progressBar);
loginTask.doInBackground();
which I now realize is probably an anti pattern -- it only works because I prefix every call to doInBackground with this...
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
So anyway, I tried to refactor it to use threads but I discovered -- that sucks!
Creating new threads every time I want to do something is super laggy and slow.
I guess this is because what I've been doing is hijacking threads from a big pre-existing pool that Android keeps around somewhere.
So I'm wondering - is there a more idiomatic way of hijacking those threads, or - should I create my own global thread pool - or - what's the best solution?
I guess this is because what I've been doing is hijacking threads from a big pre-existing pool that android keeps around somewhere
No, you have been doing all your work on the main application thread, freezing your UI. Basically, your AsyncTask is pointless.
is there a more idiomatic way of hijacking those threads
You are not "hijacking" any threads.
creating new threads every time I want to do something is super laggy and slow
We cannot help you with that, as your question does not contain any code demonstrating what you tried and explaining what specifically is "super laggy and slow".
should I create my own global thread pool
Using an Executor of some form is certainly a possibility — see the Executors class for various factory methods (e.g., newSingleThreadPool()). So is using RxJava. When you eventually switch from Java to Kotlin, coroutines become an option.
Depending on what you are trying to do, you might not need any of that. For example, the StrictMode hack you are using is frequently a reaction to getting a NetworkOnMainThreadException. Many networking libraries already exist with built-in threading support:
OkHttp for general-purpose HTTP operations
Retrofit for invoking REST-style Web services
Apollo-Android for invoking GraphQL Web services
Glide and Picasso for loading images
etc.
So, you might consider whether one of those would allow you to reduce or eliminate the amount of thread management that you need to mess with yourself.
I have to send four different request in an api at the same time. Do i need to make AsyncTask background thread for each request or all request could be done through a single AsyncTask. Can somebody please help.
This is a concurrency issue. There is literally dozens of ways to do this in Android. I've written almost every single one for courses that cover this material... and even then it isn't 'simple'.
I'd personally make use of HaMeR (Handler, Messages, Runnable) framework of Android. Create 4 runnables and have them post their results to a Handler.
However... That isn't the easiest to implement. and would require you to understand how to safely create your own custom handler (making use of WeakReference properly, etc.)
Therefore, I'd recommend running the asyncTask(s) on the executorService
myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); The default thread pool executor should start with 4 threads (I believe off-hand without looking it up).
I am assuming you are using HttpURLConnections. Unfortunately each of those connections, as specified in the documentation, is capable of handling only a single request.
However, you can (and possibly should) still perform all your requests in a single AsyncTask. Each AsyncTask will require the creation of a new thread which takes lots of time and resources. So don't listen to anyone who tells you to create a new task for each request.
You also have the option of exploiting HTTP persistence. If you add the header Connection: Keep-Alive to your request via connection.setRequestProperty("Connection", "Keep-Alive");, you will be able to send multiple requests over the same connection and save a lot of time and resources.
It's a little complicated in Java, because of the one-request-per-httpurlconnection rule, but it can be done. First, when you are done with your first request's HttpURLConnection do not close that connection. Then, to create the next connection, call url.openConnection() on the same URL object that you used to create your first HttpURLConnection. The JVM will know to reuse that connection if possible to save bandwidth.
You also have the option of using HTTP/2.0 multiplexing, which allows you to send multiple requests literally at the same time. Unfortunately I am not yet well versed enough in HTTP/2.0 to tell you exactly how to make use of this, but the multiplexing feature was included to solve exactly this problem.
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.
In an Android app, I have to make multiple GET requests to a URL in order to transmit data to an external server (that's how the third party API works).
Data comes in sporadically. I store this data in a queue and want to send it to the server in a background asynchronously without slowing down the main UI thread. Each unit of data in the queue requires a GET request. The queue has to be emptied even if the app closes.
What's the best practice to do this? Please post/direct me to code/tutorials.
What's the best practice to do this?
That would depend on what "this" is and where this work is being done.
If "this" is "asynchronous work", you will use threads in one form or fashion:
If your HTTP operations are driving a UI, you might use AsyncTask, so you can update the UI safely from onPostExecute()
If your HTTP operations are purely in the background, and you want to do one at a time, use an IntentService, which has its own background thread and work queue
If your HTTP operations are purely in the background, and you want to do one at at time, and you are concerned about ensuring that the device should stay awake while all this is going on, consider my WakefulIntentService
If your HTTP operations are purely in the background, but you feel that you want to do several at a time, roll your own Service that uses an Executor with your own thread pool, making sure that you shut down that service when the work is done (as IntentService does), and making sure that the device stays awake with a WakeLock (and perhaps a WifiLock)
Etc.
If "this" is "HTTP GET" requests, use:
HttpUrlConnection, or
HttpClient, or
OkHttp (wrapper around those with added benefits), or
Retrofit (if your GET requests are really Web service calls), or
Volley (if you like your HTTP wrapper code to be undocumented, unsupported, but Googly)
Any number of other third-party wrapper libraries
If "this" is "queue", use the Queue class, or LinkedBlockingQueue if you plan on having multiple threads work with it at once.
If "this" is something else, I can't help you, as I'm tired of guessing.
You could do your own async HTTP GET calls using AsyncTask but I would recommend against it unless you're doing it from a learning point of view. If you want a nice, clean and stable solution I'd suggest that you use the well known Android Asynchronous Http Client 3rd party library. From the site:
"An asynchronous callback-based Http client for Android built on top of Apache’s HttpClient libraries. All requests are made outside of your app’s main UI thread, but any callback logic will be executed on the same thread as the callback was created using Android’s Handler message passing."
Making a GET is as easy as:
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String response) {
System.out.println(response);
}
});