Hello:
Developing De-coupled applications always helps in maintainability of the project. In android application development we use listener pattern using interfaces to handle callback. Though it gets the work done but with bigger projects this may result into maintainability issues.
In this post I will explain how to use Android Volley with EventBus without interface listeners.
Volley: This library makes network calls and caching very easy. More info can be found here.
EventBus: This tiny library helps in implementing subscriber-publisher model with ease. More info can be found here.
Let us start.
Hope this helps. Happy coding.
Developing De-coupled applications always helps in maintainability of the project. In android application development we use listener pattern using interfaces to handle callback. Though it gets the work done but with bigger projects this may result into maintainability issues.
In this post I will explain how to use Android Volley with EventBus without interface listeners.
Volley: This library makes network calls and caching very easy. More info can be found here.
EventBus: This tiny library helps in implementing subscriber-publisher model with ease. More info can be found here.
Let us start.
- We will create a blank Project using Android Studio
- In the build.gradle add following dependencies
compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.mcxiaoke.volley:library:1.0.17' compile 'de.greenrobot:eventbus:2.4.0' compile 'com.google.code.gson:gson:2.3.1'
-
Create class VolleyManager.java. This is singleton class for Volley.
public class VolleyManager { private static VolleyManager instance; private RequestQueue mRequestQueue; public synchronized static void initialize(Context context) { if (instance == null) { instance = new VolleyManager(); instance.mRequestQueue = Volley.newRequestQueue(context); } } public synchronized static VolleyManager getInstance() { return instance; } public RequestQueue getRequestQueue() { return mRequestQueue; } }
-
BaseApplication to extend Applicaton class.
public class BaseApplication extends Application { @Override public void onCreate() { super.onCreate(); VolleyManager.initialize(this); } }
-
Create class HTTPRequestManager.java. This class will responsible for making network call using Volley
public class HTTPRequestManager<P extends BaseSuccessEvent, Q extends BaseErrorEvent> { public static final String TAG = HTTPRequestManager.class.getSimpleName(); public boolean isBaseActivity; ProgressDialog progressDialog; int responseCode; ErrorData errorData; Response.Listener<JSONObject> jsonResponseListener; Response.ErrorListener errorListener; EventBus eventBus = EventBus.getDefault(); private HashMap<String, String> params; private HashMap<String, String> headers; private String url; private Context context; private Class<P> pClass; private Class<Q> qClass; public HTTPRequestManager(Context context, String url, Class<P> pClass, Class<Q> qClass) { this.context = context; this.url = url; params = new HashMap<>(); headers = new HashMap<>(); addJSONHeaders(); errorData = new ErrorData(); isBaseActivity = true; this.pClass = pClass; this.qClass = qClass; setListeners(); } private void addJSONHeaders() { AddHeader("Accept", "application/json"); AddHeader("Content-type", "application/json"); } private void setListeners() { jsonResponseListener = new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { dismissProgressDialog(); try { P res = pClass.newInstance(); res.setResponse(response.toString()); eventBus.post(res); } catch (Exception e) { e.printStackTrace(); } } }; errorListener = new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { dismissProgressDialog(); try { Q err = qClass.newInstance(); ErrorData errorData = new ErrorData(); errorData.setMessage(error.toString()); err.setErrorData(errorData); eventBus.post(err); } catch (Exception e) { e.printStackTrace(); } } }; } public HashMap<String, String> getParams() { return params; } public HashMap<String, String> getHeaders() { return headers; } public String getCompleteUrl() { return url; } public int getResponseCode() { return responseCode; } public ErrorData getErrorData() { return errorData; } public void execute() { progressDialog = new ProgressDialog(context); progressDialog.setCancelable(false); dismissProgressDialog(); progressDialog.show(); addToRequestQueue(getJsonRequest()); } public void dismissProgressDialog() { if (progressDialog != null && progressDialog.isShowing()) { progressDialog.dismiss(); } } private <X> void addToRequestQueue(Request<X> req, String tag) { req.setTag(TextUtils.isEmpty(tag) ? TAG : tag); VolleyManager.getInstance().getRequestQueue().add(req); } private <X> void addToRequestQueue(Request<X> req) { addToRequestQueue(req, ""); } public void AddParam(String name, String value) { params.put(name, value); } public void AddHeader(String name, String value) { headers.put(name, value); } Request<JSONObject> getJsonRequest() { try { getUrl(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return new JsonObjectRequest(Request.Method.GET, url, jsonResponseListener, errorListener) { @Override public Map<String, String> getHeaders() throws AuthFailureError { return headers; } @Override protected Map<String, String> getParams() { return params; } }; } void getUrl() throws UnsupportedEncodingException { String combinedParams = ""; if (!params.isEmpty()) { combinedParams += "?"; for (Map.Entry<String, String> entry : params.entrySet()) { String paramString = entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), "UTF-8"); if (combinedParams.length() > 1) { combinedParams += "&" + paramString; } else { combinedParams += paramString; } } } url = url + combinedParams; } }
- Because of Type Erasure in Java we can't use generic events with EventBus.
We will create BaseEvents for Success and Error and then extend them for specific events
BaseSuccessEvent
public class BaseSuccessEvent { private String response; public String getResponse() { return response; } public void setResponse(String response) { this.response = response; } public <T> T getTypedResponse(Class<T> tClass) throws ClassNotFoundException { return Json.deSerialize(response, tClass); } }
BaseErrorEvent
public class BaseErrorEvent { private ErrorData errorData; public ErrorData getErrorData() { return errorData; } public void setErrorData(ErrorData errorData) { this.errorData = errorData; } }
- Now all set to use these
In the activity where we want to make network calls, code will look this
public class MainActivity extends ActionBarActivity { static String TAG = "VolleyEventBus"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.getDefault().register(this); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } @EventBusHook public void onEvent(GithubUserSuccessEvent githubUserSuccessEvent) { Toast.makeText(this, "Success", Toast.LENGTH_SHORT).show(); Log.d(TAG, githubUserSuccessEvent.getResponse()); } @EventBusHook public void onEvent(GithubUserErrorEvent githubUserErrorEvent) { Toast.makeText(this, "Error occurred.", Toast.LENGTH_SHORT).show(); Log.d(TAG, githubUserErrorEvent.getErrorData().getMessage()); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); Button requests = (Button) findViewById(R.id.requests); requests.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { HTTPRequestManager<GithubUserSuccessEvent, GithubUserErrorEvent> request = new HTTPRequestManager<>(MainActivity.this, "https://api.github.com/users/ashwanikumar04", GithubUserSuccessEvent.class, GithubUserErrorEvent.class); request.execute(); } }); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
Hope this helps. Happy coding.
Thanks for printing this post. Hope you liked it.
Keep visiting and sharing.
Thanks,
Ashwani.
Keep visiting and sharing.
Thanks,
Ashwani.
If i want to make more than one http request in single activity or fragment then how i can handle this on this pattern
ReplyDeleteHi,
DeleteYou can make as many calls you want. You will have different event for each call, thus eventbus will call corresponding method.
I'm stuck :/
ReplyDeleteI'm a beginner so sorry about (for you) trivial question).
From where did you get ErrorData type ? I've copied all to my project and I have this in red :/
and also in BaseSuccessEvent.class you return Json.deSerialize(response, tClass); Json is also in red, android studio cannot resolve symbol
my gradle deps are a bit different than your
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.volley:volley:1.0.0'
compile 'org.greenrobot:eventbus:3.0.0'
compile 'com.google.code.gson:gson:2.4'
Json is a helper class: https://github.com/ashwanikumar04/volleyeventbus/blob/master/app/src/main/java/ashwani/in/volleyeventbus/utils/Json.java
DeleteErrorData: https://github.com/ashwanikumar04/volleyeventbus/blob/master/app/src/main/java/ashwani/in/volleyeventbus/entities/ErrorData.java
VolleyManager.getInstance().getRequestQueue().add(req);
ReplyDeleteSe puede arreglar con :
public class VolleyManager{
private static VolleyManager mInstance;
private static Context mCtx;
private RequestQueue mRequestQueue;
private VolleyManager(Context context) {
mCtx = context;
mRequestQueue = getRequestQueue();
}
public static synchronized VolleyManager getInstance(Context context) {
if (mInstance == null) {
mInstance = new VolleyManager(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
Cache cache = new DiskBasedCache(mCtx.getCacheDir(), 10 * 1024 * 1024);
Network network = new BasicNetwork(new HurlStack());
mRequestQueue = new RequestQueue(cache, network);
mRequestQueue.start();
}
return mRequestQueue;
}
}