Android Volley: Static vs Object - java

I am a junior android developer and I almost finished the alpha version of my first big project. I think that I have good knowledge of java but I am not sure if I organized my app right.
Short description: I use in my app the volley library to send and receive data from server. Because of that I created a class to manage server methods. In that class I created a lot of static methods for every connection to server I need(like this example):
public static void sendDataToServer(final Context context, final String data) {
StringRequest mStringRequest = new StringRequest(Request.Method.POST, URL_VERIFY, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// get response
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// get error response
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
// the POST parameters:
params.put(API_KEY, API_KEY_VALUE);
params.put(API_KEY_DATA, data);
return params;
}
};
Volley.newRequestQueue(context).add(mStringRequest);
}
So in my activities I call this like MyServerClass.sendDataToServer(...)
My question is: Is it ok to call my server methods like that? Or should I make them instance methods and instantiate MyServerClass when activity is started? I must mention that I have about 5 methods in that class.
I have another class like that with methods to check data accuracy. Should I also make them instance methods and instantiate it in the activities I need?
Any reference or advice is welcome. Thanks in advance!

No, in your case, both ways will have the same result...
The only thing to mention is, that if you need to receive the response to your request too (may be in the future), you will need to add a Delegate / Callback / Interface to your class, to get the result right back to your calling activity instance... In that case it would be better to create a "non-static instance method" way... But you can add a non-static Method to your Class too so I don't see anything against it.
UPDATE TO COMMENT
Well for example, if you want to provide a ListView with Images... In most cases you first request an JSONArray with your ListView entries, which contains the links to Bitmaps located on the remote Server...
If you download Images Async and put them into the ImageViews in the rows of a ListView (while the user scrolls), it could be possible that images are loaded longer and the ListView will show images in wrong places... For something like that you will need a Singleton Pattern, which will manage the downloads for you... This will not be possible with your class/static Method

Although this question has already had an accepted answer, however, I'd like to share my code that looks like your issue. Hope this helps!
I also use Interface like #Neo answer, as the following:
public interface VolleyResponseListener {
void onError(String message);
void onResponse(Object response);
}
Then in my VolleyUtils class:
public static void makeJsonObjectRequest(Context context, String url, final VolleyResponseListener listener) {
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
listener.onResponse(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
listener.onError(error.toString());
}
}) {
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
return Response.success(new JSONObject(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
};
// Access the RequestQueue through singleton class.
VolleySingleton.getInstance(context).addToRequestQueue(jsonObjectRequest);
}
Then in Activity:
VolleyUtils.makeJsonObjectRequest(mContext, url, new VolleyResponseListener() {
#Override
public void onError(String message) {
}
#Override
public void onResponse(Object response) {
}
});
P/S: my project uses Google's official Volley library, instead of using compile 'com.mcxiaoke.volley:library:1.0.17' in build.gradle. As a result, JsonObjectRequest(...) will have a difference at its definition.

Related

How to notify UI on volley success MVVM architecture

I am using mvvm architecture I would like to notify view when volley post request is successful, what i could do is to instantiate ViewModel in appRepository class and then post values to a liveData, but i guess that's not a good approach as I haven't seen a similar practice. Can anyone suggest me a good approach to return my response to ui, or at least notify that post request has been successful.
From fragment/View I trigger this method
// save data to api
checkInViewModel.updateEventPersonEntity(eventPersonsEntity);
ViewModel forwards it to apprespository
public void updateEventPersonEntity(EventPersonsEntity eventPersonsEntity) {
mRepository.updateEventPersonEntity(eventPersonsEntity);
}
AppRepository.Java class
public void updateEventPersonEntity(EventPersonsEntity eventPersonsEntity) {
executor.execute(() -> {
// mDb.eventPersonsDao().update(eventPersonsEntity);
if (isNetworkAvailable(context)) {
post_updateEventPersonEntity(eventPersonsEntity);
}
});
}
private void post_updateEventPersonEntity(EventPersonsEntity eventPersonsEntity) {
Map<String, Object> params = new HashMap<>();
params.put("EventPersonId", eventPersonsEntity.getEventPersonId());
params.put("EventId", eventPersonsEntity.getEventId());
params.put("PersonId", eventPersonsEntity.getPersonId());
params.put("CashStart", parseDoubleToGerman(eventPersonsEntity.getCashStart()));
params.put("CashEnd", parseDoubleToGerman(eventPersonsEntity.getCashEnd()));
params.put("StartingTime", String.valueOf(eventPersonsEntity.getStartingTime()));
params.put("EndingTime", String.valueOf(eventPersonsEntity.getEndingTime()));
params.put("isChekcedIn", eventPersonsEntity.getIsCheckedIn());
params.put("isChekcedOut", eventPersonsEntity.getIsCheckedOut());
JSONObject objRegData = new JSONObject(params);
String eventPersonApi = APP_URL.EVENT_PERSONS_API + eventPersonsEntity.getEventPersonId();
RequestQueueSingleton.getInstance(context).objectRequest(eventPersonApi, Request.Method.PUT, this::onSuccess_updateEventPersonEntity, this::onError, objRegData);
}
private void onError(VolleyError error) {
Log.d(APP_REPOSITORY_TAG, "requestError: " + error);
}
private void onSuccess_updateEventPersonEntity(JSONObject jsonObject) {
// notify ui
}
You can do this same as you did for your success response logic in repository. Simply create new callback interface:
interface OnEventUpdatedListener{
void eventUpdated();
}
Then, update your method to look like this, passing the listener to the actual method that does the work:
public void updateEventPersonEntity(EventPersonsEntity eventPersonsEntity, OnEventUpdatedListener listener) {
mRepository.updateEventPersonEntity(eventPersonsEntity, listener);
}
Pass this inside your:
if (isNetworkAvailable(context)) {
post_updateEventPersonEntity(eventPersonsEntity, listener);
}
After that, in your onSuccess() method simply call:
private void onSuccess_updateEventPersonEntity(JSONObject jsonObject) {
listener.eventUpdated();
}
Finally, you will have the info when the update happens, in the calling site, if you call your repository like this:
updateEventPersonEntity(null, new OnEventUpdatedListener() {
#Override
public void EventUpdated() {
// Do your logic here
}
});

Android String.format() Crash with no reason

I am having a strange crash/error that happened without changing anything.
I am using Volley for network requests and i have a separate class with my URL end points.
I am using MY_REQUEST_URL + myparam=%s as the link and in the volley request i am using String.format(EndPoints.MY_REQUEST_URL, myparameter) and when I run this request in my app, it crashes (see the log below).
What is even stranger is that i am using the same type of requests in the same app and they all work fine except this and another one.
MyClass code:
public class MyClass extends Fragment{
// other declarations
ArrayList<JSONObject> data;
View view
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_myclass, null);
// initializing lots of views
data = new ArrayList<JSONObject>();
String userid = Utils.getStringFromPreferences(getActivity(), Utils.VAR_USERID); // this is a custom method of getting from shared preferences, it is static in my custom Utils class
getData(userid);
return view;
}
//different methods
//getData Method
private void getData(String userid) {
String url = String.format(EndPoints.URL_MY_REQUEST_URL, userid);
Log.d("request url debug", url);
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Result handling
Log.e("data", response);
if (!response.equals("") || response != null) {
try {
// response handling
} catch (JSONException e) {
// e.printStackTrace();
}
} else {
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println("Something went wrong!");
error.printStackTrace();
}
});
stringRequest.setRetryPolicy(new DefaultRetryPolicy(
10000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
// Add the request to the queue - i have a custom class for this, used in every network request that works fine
VolleyRequestQue.getInstance(InsuitBusiness.getContext()).addToRequestQueue(stringRequest);
}
}
This is the Endpoints class:
public class Endpoints {
public static String MY_MAIN_URL = "https://www.myweb.com/"
public static String MY_REQUEST_URL = MY_MAIN_URL + "scripts/getData.php?userid=%s"
// the rest of the class is all the same like stringname = MY_MAIN_URL + "phpscript.php?parameter=%s"
}
This is the error log:
Caused by: java.util.MissingFormatArgumentException: Format specifier '%s'
at java.util.Formatter.format(Formatter.java:2490)
at java.util.Formatter.format(Formatter.java:2426)
at java.lang.String.format(String.java:2626)
at com.myapp.myapp.MyClass.getData(MyClass.java:1220)
at com.myapp.myapp.MyClass$getDataAsync.doInBackground(MyClass.java:1208)
at com.myapp.myapp.MyClass$getDataAsync.doInBackground(MyClass.java:1204)
at android.os.AsyncTask$2.call(AsyncTask.java:304)
MY_MAIN_URL which was supposed to have as value: "https://www.myweb.com/" i was mistakenly giving another value which contained "%s" and this is how i got the exception and the crash.
For future people having the same problem just make sure there aren't more "%s" in the link, Log the link in the debugger and see how it shows up.
Thanks to everyone for their time.

Android - Java Equivalent Of iOS Block Callbacks?

In my Android app, I'd like to implement success and error callbacks for when I get reading passages from my backend. In iOS, it would look like this:
In my Passage.h:
-(void)getPassagesWithSuccessCallback:(void (^)(NSArray<Passage *> *))success errorCallback:(void (^)(NSString *))errorString;
In my Passage.m:
-(void)getPassagesWithSuccessCallback:(void (^)(NSArray<Passage *> *))success errorCallback:(void (^)(NSString *))errorString {
MyApiInterface* api = [MyApiInterface sharedInstance];
[api sendGetRequestTo:#"passages" successCallback:[Passage modelListCallback:success] errorCallback:error];
}
In my Android app, I'm using Volley to handle my API requests, but I want to further encapsulate this API interfacing by having a Passage.java class with a public static void method that gets the passages. Something like this:
public static void getPassagesForFirebaseUser(FirebaseUser user, Context context) {
final String url = URL_BASE + "/passages.json" + "?auth=" + user.getToken(false);
final JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// convert JSON into ArrayList<Passage> object
// pass on this array of Passages in the success completion listener of the method that called this
// just like iOS does success(passages)
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// convert error to string
// pass on this errorString in the error completion listener of the method that called this
// just like iOS does error(errorString)
}
});
Volley.newRequestQueue(context).add(request);
}
Is there any way to get this kind of implementation flow?
You can use an Interface
public interface ICallbacks {
public void onResponse(JSONObject response);
public void onError(VolleyError error);
}
Then in your routine code just put a new instance of Callbacks (depending on ide that you work could autogenerate the methods)
public static void getPassagesForFirebaseUser(FirebaseUser user,
Context context, ICallbacks events) {
//here code and call ICallbacks methods
if(result){ events.onResponse(response); }
if(error){ events.onError(err); }
}
ultimately you can call the method with :
getPassagesForFirebaseUser(user, context, new ICallbacks(){
#Override
public void onResponse(JSONObject response){
//Success !!!
}
#Override
public void onError(VolleyError response){
//Error !!!
}
});
Sorry for my English, hope this help !

Callback function in Android

I am using Volley to make Http requests to my Web Api.
However I am having trouble getting the values from my api calls due to the asynchronous nature of Volley.
I have read that using a callback function could help with this issue, however I do not know how to implement such a solution.
How would I go about implementing a callback function in the following scenario?
public class Main
{
String name;
WebServiceConnections wsc = new WebServiceConnections();
name = wsc.getNameFromWeb();
System.out.println("Name: " + name);
}
public class WebServiceConnections
{
public String getNameFromWeb()
{
String url = "http://nameservice.net/GetName";
JsonArrayRequest req = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
try {
return response.getString("Name");
}
catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
}
});
}
}
The problem with this code is that the variable "name" in Main will be null when it is called by the print statement as the asynchronous method in the WebServiceConnections class will not be finished by time the print statement is called.
Is a callback a good way to solve this problem?
Your code doesn't compile - you can't return a value in a method with void return type.
Your onResponse method is the callback. Perform the print within the method itself.

What is the most efficient way of updating UI in Volley

lately I'm using Volley library in android.. It works fine but I was wondering about the most efficient way of updating the UI.. I have a Utils class that has all the Volley methods.. right now I pass all the Views that will be updated as parameters, but I've read that I could implement the listeners in my activity then pass them as parameters in the Utils class..
So my question is:
Which is more efficient and why updating the UI like this:
public void getSettings(final TextView exampleView) {
JsonObjectRequest jsonRequest = new JsonObjectRequest(Method.GET,
url, (String) null, new Response.Listener<JSONObject>() {
public void onResponse(JSONObject response) {
try {
final String setting = getSettingFromJSON(response);
exampleView.setText(setting);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
public void onErrorResponse(VolleyError arg0) {
}
});
app.add(jsonRequest);
}
Or I declare the listeners in my activity like this :
Response.Listener<JSONObject> listener = new Response.Listener<JSONObject>() {
public void onResponse(JSONObject response) {
String setting = Utils.getSettingFromJSON(response);
exampleView.setText(setting);
}
};
then I pass them into my utils function as parameters so the call would be like this :
utils.getSettings(listener);
instead of :
utils.getSettings(exampleView);
Thanks In Advance :)
Why not use something like EventBus to manage passing back info from the request to your activity? This way you can separate your networking code from your activities/views. The basic idea using EventBus and Volley is the following:
Register a class to receive some type of event, in this case probably
the activity
Create a method in this class to handle this event,
exampleView.setText(setting).
Post the event to the bus, post the String or volley error in the
Volley listeners.
For a more detailed example checkout this blogpost or Eventbus' github page.
As in my question Android/Java: how to delay return in a method
I also use interface listener, however, I update views in main thread, not in Utils class

Categories

Resources