11

I decided to give Volley a try, so presently I have a lot of REST callouts to be done, so I usually create a RequestHandler and a ResponseHandler class which as their names suggest handle requests and responses respectively. I follow this pattern so that I don't write redundant code. I just pass in the dynamic query/url as parameter and using a switch case handle the response to each of the requests. But I am stuck with the below problem :

I have no way of updating my UI thread from where I call the RequestHandler class. What I have tried or already know so far :

  1. Make the UI elements(Textview, Listview) static and update them after the response comes.
  2. Pass in a context parameter and update the UI after the response is received.
  3. Write the request and response as inner classes within the Activity
  4. Get rid of Volley.

I was wondering, how you guys do it? Is there any pattern better than the Request/Response Handler pattern I follow? Any way of updating the UI thread following the same pattern?

Thanks in advance !

Adnan Mulla
  • 2,872
  • 3
  • 25
  • 35

2 Answers2

3

I use volley, and this is what I do. The code goes anywhere in your activity.

import com.android.volley.Response.Listener;
import static com.android.volley.Response.ErrorListener;

Listener<YOURDATACLASS> successListener = new Listener<YOURDATACLASS>() {
    @Override
    public void onResponse(YOURDATACLASS data) {
        // Check to make sure that the activity hasn't been destroyed while the call was in flight.
        if (! isFinishing()) {
            //DO YOUR UI UPDATE, such as 
            TextView textview = (TextView) findViewById(R.id.yourtextview);
            textview.setText("blah blah blah");
        }
    }
};
ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            //DO SOMETHING ON FAILURE
        }

YOURAPICALL(successListener, failurelistener);
GLee
  • 5,003
  • 5
  • 35
  • 39
  • 1
    This will crash, if you will close an activity before network call is done. – Victor Ronin Sep 08 '14 at 21:32
  • Yes, as with all callbacks in Android you have to add checks to make sure that your view is alive. I'll add an example to the answer. – GLee Sep 12 '14 at 22:50
  • 1
    Actually, just checking it will only partially fix the problem. You will still have a race condition between your thread and UI thread – Victor Ronin Sep 13 '14 at 00:25
  • Please explain further, I don't understand from your answer below how a race condition exists that will cause a crash. The isFinishing() block will get executed on the main thread, so the activity will have to be deallocated either before or after this block on the main thread. The if statement checks for that condition. Also, have you seen such a crash in practice? – GLee Sep 14 '14 at 17:22
  • Actually, you are right. I was under wrong impression that callback is called on a separate thread. How does system behave in such case, if activity was closed long time ago? – Victor Ronin Sep 14 '14 at 19:22
  • In my experience, I had crashes from callbacks trying to update the UI after the activity was destroyed, as you originally pointed out. This if statement fixed them. However, our code is littered with these ugly checks in the volley callbacks, which is not ideal. I don't have a solution to that. – GLee Sep 15 '14 at 19:32
  • you should send out your calls in a service and communicate back with your activity if it still is bind to the service – feisal Jan 21 '15 at 00:15
  • 1
    If you, at any point, get to crashes caused by callbacks from Volley, I have a solution: Implement `@Override onDestroy()` that calls `RequestQue.cancelAll()` (do not forget to call `super.onDestroy()`. Using that you will prevent accessing Views that do not exist. – FanaticD Feb 28 '16 at 07:11
  • @FanaticD What if some requests have been received, but some of them are still to be received. Can we call somethings like RequestQueue.cancelPendingRequests() ? – ARK Mar 18 '16 at 18:20
  • @akshayrajkore This post answers your question, I believe: http://stackoverflow.com/a/29051610/3444151 – FanaticD Mar 18 '16 at 18:28
  • @FanaticD Thanks for sharing. I want to confirm: requests that have been started, cannot be cancelled. To handle the scenario when request has begun, and then activity is paused, we check if getActivity == null ? – ARK Mar 18 '16 at 18:39
0

This works for me.

Map<String, String> params = new HashMap<>();
    params.put("dep", DEP);

    CustomPostRequest request = new CustomPostRequest(Request.Method.POST, Uris.URL_GET_DEP_CAT, params,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject jsonObject) {

                    List<PCatValues> valores = parsear_y_devolver_valores(jsonObject);

                    gestionar_entregas(valores);

                    //aqui quitar los dialogos

                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError volleyError) {

        }
    });

    ApiController.getInstance().addToRequestQueue(request);

ApiController is my Aplication singleton class.

public class ApiController extends Application {

public static final String TAG = ApiController.class.getSimpleName();

private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;

private static ApiController mInstance;

@Override
public void onCreate() {
    super.onCreate();
    mInstance = this;
    /*FacebookSdk.sdkInitialize(getApplicationContext());
    try {
        PackageInfo info = getPackageManager().getPackageInfo(
                "com.example.android.facebookloginsample",  // replace with your unique package name
                PackageManager.GET_SIGNATURES);
        for (Signature signature : info.signatures) {
            MessageDigest md = MessageDigest.getInstance("SHA");
            md.update(signature.toByteArray());
            Log.e("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT));
        }
    } catch (PackageManager.NameNotFoundException e) {

    } catch (NoSuchAlgorithmException e) {

    }*/

}

public static synchronized ApiController getInstance() {
    return mInstance;
}

public RequestQueue getRequestQueue() {
    if (mRequestQueue == null) {
        mRequestQueue = Volley.newRequestQueue(getApplicationContext());
    }
    return mRequestQueue;
}

public <T> void addToRequestQueue(Request<T> req, String tag) {
    req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
    getRequestQueue().add(req);
}

public <T> void addToRequestQueue(Request<T> req) {
    req.setTag(TAG);
    getRequestQueue().add(req);
}

public void cancelPendingRequests(Object tag) {

    if (mRequestQueue != null) {
        mRequestQueue.cancelAll(tag);
    }

}

}

carrasc0
  • 358
  • 2
  • 9