Okhttp Response Callbacks on the Main Thread

Okhttp response callbacks on the main thread

From my understanding, Okhttp callbacks run on the main thread so why do I get this error ?

This is not true. Callbacks run on a background thread. If you want to immediately process something in the UI you will need to post to the main thread.

Since you already have a wrapper around the callback you can do this internally in your helper so that all HttpCallback methods are invoked on the main thread for convenience.

How to get async call to return response to main thread, using okhttp?

Common way to get results from asynchronous world to synchronous (thread-based) is to use Futures. Many libraries implement such an interface, e.g. Guava. Standard java has implementation named CompletableFuture. It uses methods with different names and signatures, but an adapter can be easily implemented:

class CallbackFuture extends CompletableFuture<Response> implements Callback {
public void onResponse(Call call, Response response) {
super.complete(response);
}
public void onFailure(Call call, IOException e){
super.completeExceptionally(e);
}
}

Then you can use it as follows:

CallbackFuture future = new CallbackFuture();
client.newCall(request).enqueue(future);
Response response = future.get();

Having the Response, you can extract responseString the same way as you did it in the your first variant.

NetworkOnMainThreadException when trying to run okhttp response code on UI thread

This should work:

override fun onResponse(call: Call?, response: Response?) {                           
val body = response?.body()?.string()
this@MainActivity.runOnUiThread { textView.text = body }
}

You shouldn't access the response on the UI thread as it is considered a IO operation.

OkHTTP Update UI from enqueue callback

You can refer to the following sample code, hope this helps!

public class MainActivity extends AppCompatActivity {
private static final String LOG_TAG = "OkHttp";
private TextView mTextView;
private Handler mHandler;
private String mMessage;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
mHandler = new Handler(Looper.getMainLooper());
OkHttpClient client = new OkHttpClient();
// GET request
Request request = new Request.Builder()
.url("http://...")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
mMessage = e.toString();
Log.e(LOG_TAG, mMessage); // no need inside run()
mHandler.post(new Runnable() {
@Override
public void run() {
mTextView.setText(mMessage); // must be inside run()
}
});
}

@Override
public void onResponse(Response response) throws IOException {
mMessage = response.toString();
Log.i(LOG_TAG, mMessage); // no need inside run()
mHandler.post(new Runnable() {
@Override
public void run() {
mTextView.setText(mMessage); // must be inside run()
}
});
}
});
}
}

Waiting for thread to complete OkHttp Call

In this case you should be using execute as mentioned and since http calls are handled asynchronously your thread is redundant and should be removed.

If you want to run code after all the requests are finished one way of doing this is by passing in a onComplete callback function and count the number of requests completed, when all of the threads are completed call the callback function containing the code that should be run after all of the requests.

Android how to get response string from Callback using OkHttp?

I think what you want to do is something like this:

public class MyActivity extends Activity implements Callback , View.OnClickListener {

@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
findViewById(R.id.DoHttp).setOnClickListener(this);
}

@Override
public void onClick(View v) {
if (v.getId(() == R.id.DoHttp) {

OkHttpClient okHttpClient = new OkHttpClient();

Request request = new Request.Builder().url("http://publicobject.com/helloworld.txt").build();
okHttpClient.newCall(request).enqueue(this);
}
}

@Override
public void onFailure(Request request, IOException e) {
//do something to indicate error
}

@Override
public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
parse(response.body().string());
}
}

private void parse(String response) {
//do something with response
}
}

In the above activity we implement Callback and then when we create the okhttp request, we pass it an instance of ourself (this) and that way we can get oktthp to call back the class, we could have done an inner class just as easily but this reduces the # of classes we have to make. I used a button click to illustrate when the Http call is made but that could be some other time, for instance it could happen when the screen is first created (in onCreate). Be careful though of screen rotations. Also this assumes that the callback is done on the main thread which I think it would be but I'm not positive as I use okttp in a different way than you. If it does not return the results on the response on the main thread then you can call runOnUiThread() and pass it a Runnable that does the work of updating the views.

getting String response from OKhttp

The problem here is about understanding how asynchronous tasks work. When you are calling client.newCall(request).enqueue(new Callback(), it will run in the background thread (off the main thread) and control will pass to the next line which is return mJsonResponce; And thus, it will always return null.

What you should do is to pass a callback method which will be called when the response is successful. You can create an interface to return the result:

public interface NetworkCallback {
void onSuccess(String repsonse);
void onFailure();
}

Pass an object of this interface while making the network request and call appropriate method when network request finishes.

One more thing you will have take care is that OkHttp doesn't return the response on the main thread so you will have to return the response on UI/main thread if you are going to update any UI. Something like this will work.

@Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//return response from here to update any UI
networkCallback.onSuccess(response.body().string());
}
});
}
}

Does Retrofit make network calls on main thread?

Retrofit methods can be declared for either synchronous or asynchronous execution.

A method with a return type will be executed synchronously.

@GET("/user/{id}/photo")
Photo getUserPhoto(@Path("id") int id);

Asynchronous execution requires the last parameter of the method be a Callback.

@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);

On Android, callbacks will be executed on the main thread. For desktop applications callbacks will happen on the same thread that executed the HTTP request.

Retrofit also integrates RxJava to support methods with a return type of rx.Observable

@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);

Observable requests are subscribed asynchronously and observed on the same thread that executed the HTTP request. To observe on a different thread (e.g. Android's main thread) call observeOn(Scheduler) on the returned Observable.

Note: The RxJava integration is experimental.

Trying to implement the okHttp Call & Callback scenario. Upon completion there is no onPostExecute to modify the UI

The callback is not called on the main thread. If you need to update the UI, a simple way to do that is to create a class that implemented Callback and post the items to the UI like so:

  public abstract class UIMainCallback implements Callback {
private static final Handler mUIHandler = new Handler(Looper.getMainLooper());

abstract void failure(Request request, IOException e);

abstract void response(Response response);

@Override
public void onFailure(final Request request, final IOException e) {
mUIHandler.post(new Runnable() {
@Override
public void run() {
failure(request, e);
}
});
}

@Override
public void onResponse(final Response response) throws IOException {
mUIHandler.post(new Runnable() {
@Override
public void run() {
response(response);
}
});
}
}

Then your Caller can just implement the UIMainCallback instead of the interface.



Related Topics



Leave a reply



Submit