I am using the ion library to download the json object response from php web services.
I am using it this way :
Ion.with(getActivity())
.load("http://amd.com/loginService.php")
.progressBar(progressBar).progress(new ProgressCallback() {
#Override
public void onProgress(long downloaded, long total) {
int mProgress = (int) (100 * downloaded / total);
progressBar.setProgress(mProgress);
}
})
.setMultipartParameter("fb_id", id)
.setMultipartParameter("fb_token", AccessToken.getCurrentAccessToken().toString())
.asJsonObject()
.setCallback(new FutureCallback<JsonObject>() {
#Override
public void onCompleted(Exception e, JsonObject result) {
if (result == null) {
Toast.makeText(getActivity(), "Error", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
} else {
Log.v("IonResult", result.toString());
progressBar.setVisibility(View.GONE);
}
}
});
Now I want to ask two questions:
How can I show the "please wait" and the progress bar in a good manner? The progress bar should appear and then disappear when the response of server has been achieved.
How to parse the json which I am getting in response? I have logged my results like this
Log.v("IonResult", result.toString());
and I can see the response, but how can I use it and parse it and get the items I want?
Please help, I know it is a basic question, but as I am beginner in Android, please help me improve. Thanks.
I started using Ion recently, so I'm not sure if this is the best way to do that (please, if you know, leave a comment here!).
So, I'm using callbacks to return the value to another class.
public interface ResponseCallback {
public void onSuccess(String result);
public void onError(String result);
}
One example in my code:
public void getChats(final Context context, final String url,final ResponseCallback responseCallback) {
Ion.with(context)
.load(url)
.asString()
.setCallback(new FutureCallback<String>() {
#Override
public void onCompleted(Exception e, String result) {
if (e != null) {
if (responseCallback != null) {
responseCallback.onError(e.toString());
}
Toast.makeText(context, "Error loading chat list.", Toast.LENGTH_SHORT);
return;
}
if (responseCallback != null) {
responseCallback.onSuccess(result);
}
}
});
}
So, when I call getChats(), I implement ResponseCallback methods. I hope it helps, even that I think there's a better way to do that.
Related
I've been building an app which has Log In functionality. I've tested it but every time i tried to Log In, the progress bar disappeared to quickly (like a quarter second or something), and the response i get from the server is like about 2 seconds after the progress bar disappeared. Here are some of my codes.
My LoginTask inner class :
private class LoginTask extends AsyncTask<Account, Void, Account>{
private String getUsername = username.getText().toString();
private String getPassword = password.getText().toString();
#Override
protected void onPreExecute() {
super.onPreExecute();
//showDialog();
progressBar.setVisibility(View.VISIBLE);
}
#Override
protected void onPostExecute(Account account) {
super.onPostExecute(account);
//dismissDialog();
progressBar.setVisibility(View.GONE);
}
#Override
protected Account doInBackground(Account... accounts) {
getLogin(getUsername, getPassword);
return null;
}
}
Login Retrofit call to server
private void getLogin(String email, String password) {
Call<LoginAuth> call = userService.getLogin(email, password);
call.enqueue(new Callback<LoginAuth>() {
#Override
public void onResponse(Call<LoginAuth> call, Response<LoginAuth> response) {
try {
if (response.body().getToken_type().equals("xxx")) {
Log.i(TAG, "getLogin, Authorized access");
Log.i(TAG, "getLogin, access_token: " + response.body().getAccess_token().toString());
Log.i(TAG, "getLogin, expires_at" + response.body().getExpires_at().toString());
} else {
Log.e(TAG, "getLogin, Unauthorized access" + response.body().getToken_type().toString());
}
} catch (Exception e) {
Log.e(TAG, "getLogin exception " + e.getMessage());
}
}
#Override
public void onFailure(Call<LoginAuth> call, Throwable t) {
Log.e(TAG, "getLogin, onFailure : " + t.getMessage());
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast.makeText(LoginActivity.this, "Unable to Log In :(", Toast.LENGTH_SHORT).show();
}
});
}
});
}
I want it to work like when the response is fetched, that's the time the progress bar disappeared (not instantly). Did i do something wrong with the code?
As you are using retrofit, there is no necessity to call your api in separate asynctask as retrofit manages it asynchronously. what you should do is show your progressbar before you call api and dismiss it in onResponse and onFailure both. so your code would change to something like below.
private void getLogin(String email, String password) {
progressBar.setVisibility(View.VISIBLE);
Call<LoginAuth> call = userService.getLogin(email, password);
call.enqueue(new Callback<LoginAuth>() {
#Override
public void onResponse(Call<LoginAuth> call, Response<LoginAuth> response) {
progressBar.setVisibility(View.Gone);
//rest of your code
}
#Override
public void onFailure(Call<LoginAuth> call, Throwable t) {
Log.e(TAG, "getLogin, onFailure : " + t.getMessage());
progressBar.setVisibility(View.Gone);
//rest of your code
}
});
}
I am making a network call through volley. On Response success I am trying to store data through SnappyDb which shows that it has stored successfully. But while reading any data is not present. But if I have data outside of response than it saves and reads too. Below is my code. I am struggling in this from last 2 days. Your help will be highly appreciated. Thanks
private void makeApiCall(String key) {
if (Utility.isNetworkAvailable(AddCustomerActivity.this)) {
final String finalKey = key;
showProgressDailog("Adding...");
NetworkEb.apiCallAddUser(customerEb, (key != null && !key.contains(":"))? true : false, new OnJsonResponse() {
#Override
public void onSuccess(JSONObject response) {
try {
int serverId = response.getInt("id");
customerEb.setKey(serverId + "");
customerEb.setSync(true);
snappyDbUtil.saveObjectFromKey("customer", DbName.CUSTOMER.name(), customerEb);
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onError(String response) {
Utility.showToast("Upload failed! Try Again");
progressDialog.dismiss();
}
});
} else {
if (key == null) {
key = snappyDbUtil.getNewKey(DbName.CUSTOMER.name());
customerEb.setKey(key);
customerEb.setSync(false);
Utility.showToast("Saved locally");
}
snappyDbUtil.saveObjectFromKey(key, DbName.CUSTOMER.name(), customerEb);
}
}
I found a solution for this. You need to save the data in UI thread by calling this
runOnUiThread(new Runnable() {
#Override
public void run() {
itemDataModel.setKey("ITEMS:" + key);
itemDataModel.setSync(true);
snappyDbUtil.saveObjectFromKey(itemDataModel.getKey(), DbName.ITEMS.name(), itemDataModel);
}
});
Here you have to also care for the keys to store with which only saves if we provide a db name as shown in the above code.
I have a class LoginTask which is a subclass of AsyncTask. I used that to execute login functionality. Simply my LoginTask looks like this
class LoginTask extends AsyncTask<JsonObject,Void,String>{
#Override
protected void onPreExecute() {
//Codes to show progressDialog
}
#Override
protected String doInBackground(JsonObject... params) {
Ion.with(MainActivity.this)
.load("--URL TO POST JSON DATA--")
.setJsonObjectBody(params[0])
.asJsonObject()
.withResponse()
.setCallback(new FutureCallback<Response<JsonObject>>() {
#Override
public void onCompleted(Exception e, Response<JsonObject> result) {
if (result != null) {
if (result.getHeaders().code() == 200) {
Toast.makeText(MainActivity.this, "Login Success", Toast.LENGTH_SHORT).show();
} else if (result.getHeaders().code() == 401) {
Toast.makeText(MainActivity.this, "Invalid Username or password", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "Something wrong check connection !!!", Toast.LENGTH_SHORT).show();
}
}
}
});
return "some message";
}
#Override
protected void onPostExecute(String string) {
super.onPostExecute(string);
if(progressDialog.isShowing()){
progressDialog.dismiss();
//TODO Something
}
}
}
What I want and What was happened :
I want to call onPostExecute Only after getting the result from FutureCallback method But when I debug the app It is directly returning the value and onPostExecute Method called Immediately before FutureCallback method.
I have written code to Execute LoginTask at Login Button pressed Event, I want to show the ProgressDialog each time when Button is pressed, But the problem is ProgressDialog is shown only at the first time, It didn't appear when I pressed the Button second time.
I want to set some message to a variable and return that to onPostExecute method so that I can handle specific tasks based on the value of String parameter, But FutureCallback is called only after executing the whole Task.
Any Kind of Suggestions will be appreciated.
Here you are calling another thread inside asynctask. So whats happening is when the new thread is getting called. Asynctask is not waiting for your ion's thread to complete and so it is going to onPostExecute.
I think you don't need a asynctask here because Ion is already making the request asyncronously. Whatever you are doing inside onPostExecute(), you can put that inside onComplete() of the ion's call.
Do like this,
[Codes to show progressDialog]
Ion.with(MainActivity.this)
.load("--URL TO POST JSON DATA--")
.setJsonObjectBody(params[0])
.asJsonObject()
.withResponse()
.setCallback(new FutureCallback<Response<JsonObject>>()
{
#Override
public void onCompleted(Exception e, Response<JsonObject> result) {
if(progressDialog.isShowing()){
progressDialog.dismiss();
//TODO Something
}
if (result != null) {
if (result.getHeaders().code() == 200) {
Toast.makeText(MainActivity.this, "Login Success", Toast.LENGTH_SHORT).show();
} else if (result.getHeaders().code() == 401) {
Toast.makeText(MainActivity.this, "Invalid Username or password", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "Something wrong check connection !!!", Toast.LENGTH_SHORT).show();
}
}
}
});
onCompleted() method you are passing in setCallback() method is a callback method that is an asynchronous call so this callback will be invoked when response is returned from server and its takes time that is why your onPostExecute method is called before futureTask.
Ion lib already uses async calls so you do not need to use AsyncTask. You just need to do following:
Ion.with(MainActivity.this)
.load("--URL TO POST JSON DATA--")
.setJsonObjectBody(params[0])
.asJsonObject()
.withResponse()
.setCallback(new FutureCallback<Response<JsonObject>>() {
#Override
public void onCompleted(Exception e, Response<JsonObject> result) {
if (result != null) {
if (result.getHeaders().code() == 200) {
Toast.makeText(MainActivity.this, "Login Success", Toast.LENGTH_SHORT).show();
} else if (result.getHeaders().code() == 401) {
Toast.makeText(MainActivity.this, "Invalid Username or password", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "Something wrong check connection !!!", Toast.LENGTH_SHORT).show();
}
}
}
});
I start a ProgressDialog when I start my async request and on seemingly random occasions the dialogue does not dismiss (code does not fire onSuccess or onFailure). I handle both possible success responses from the server (one of which is an error) and I have a failure block so in theory the ProgressDialog should always dismiss. Can someone tell what event I am missing? Or is there a better structure?
My code structure:
I have a Gateway class that handles all the networking
The calling calls handles the .show() and .dismiss() events for the dialog
Gateway:
public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
client.post(getAbsoluteUrl(url), params, responseHandler);
}
public static void loadItems(final ItemAdapter itemAdapter, int itemID) {
final String url = String.format(Constants.URL_ITEMS, itemID);
post(url, null, new JsonHttpResponseHandler() {
#Override
public void onSuccess(JSONObject response) {
try {
if (!response.isNull("items")) {
itemAdapter.updateData(items);
} else if (!response.isNull("error")) {
itemAdapter.signalError(response.getString("error"));
}
} catch (JSONException e) {
itemAdapter.signalError("An unknown error has occurred");
e.printStackTrace();
}
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error)
{
if (error instanceof SocketTimeoutException || error instanceof ConnectTimeoutException) {
itemAdapter.signalError("Connection timeout! Please check that you are connected to the internet");
} else {
itemAdapter.signalError("An unknown error has occurred");
}
}
});
}
The adapter:
public ItemAdapter(Context context, int itemID) {
progressDialog = ProgressDialog.show(context, "Items",
"Loading items", true);
Gateway.loadItems(this, itemID);
}
public void updateData(ArrayList<Items> items) {
progressDialog.dismiss();
this.items = items;
notifyDataSetChanged();
}
public void signalError(String errorMessage) {
progressDialog.dismiss();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Error")
.setMessage(errorMessage)
.setNegativeButton("OK", null).show();
}
I have no idea what your code is doing, but your if statements look suspicious.
if (!response.isNull("items")) {
itemAdapter.updateData(items);
} else if (!response.isNull("error")) {
itemAdapter.signalError(response.getString("error"));
}
could it be that none of the two conditions are met? If so, the dialog will not be dismissed. You only dismiss it on exception or if one of the above conditions are met.
I read somewhere that there is a design flaw in the library and people had some problems with the same issue.
But the most reliable solution was to override all the onSuccess and onFailure methods in the JsonHttpResponseHandler. In that way you can be sure that a communication is going on.
Hope this helps
Handle else case also onSuccess method like
#Override
public void onSuccess(JSONObject response) {
try {
if (!response.isNull("items")) {
itemAdapter.updateData(items);
} else if (!response.isNull("error")) {
itemAdapter.signalError(response.getString("error"));
} else {
// Code to dismiss the dialog
}
} catch (JSONException e) {
itemAdapter.signalError("An unknown error has occurred");
e.printStackTrace();
}
}
If your main concern is just closing ProgressDialog .. then try like this .
try{
runOnUiThread(new Runnable() {
public void run() {
progressDialog.dismiss();
}
});
}catch(Exception beauty)
{
// Log error if any ..
}
Hope it helps!
I am trying to access user information from facebook sdk.But I keep getting this error.
{"error":{"message":"Error validating access token: The session has been invalidated because the user has changed the password.","type":"OAuthException","code":190,"error_subcode":460}}
Here is the call which returns me the error in the response parameter of the oncomplete function.
mAsyncRunner.request("me", new RequestListener() {
#Override
public void onComplete(String response, Object state) {
Log.d("Profile", response);
String json = response; //<-- error in response
try {
JSONObject profile = new JSONObject(json);
MainActivity.this.userid = profile.getString("id");
new GetUserProfilePic().execute();
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Name: " + MainActivity.this.userid, Toast.LENGTH_LONG).show();
}
});
} catch (JSONException e) {
e.printStackTrace();
Log.e("jsonexception",e.getMessage());
facebook.extendAccessTokenIfNeeded(MainActivity.this, null);
GetUserInfo();
}
}
#Override
public void onIOException(IOException e, Object state) {
}
#Override
public void onFileNotFoundException(FileNotFoundException e,
Object state) {
}
#Override
public void onMalformedURLException(MalformedURLException e,
Object state) {
}
#Override
public void onFacebookError(FacebookError e, Object state) {
}
});
Sometimes I get the correct response also.I think this is due to the access token expiration if I am right.
So can you guys tell me how to extend the access token although I've used this facebook.extendAccessTokenIfNeeded(this, null); in the onResume method of the activity.
How to solve this?
Both the extendAccessTokenIfNeeded and extendAccessTokenIfNeeded methods require the native Facebook app to be installed locally.
(I don't know if you are using v2 or v3b of the SDK, but it's documented here https://developers.facebook.com/docs/reference/android/3.0/Facebook#extendAccessToken(Context,%20ServiceListener) )
The behavior you're seeing... is it in the emulator or a real device? If the former, you can install the native Facebook app as an APK from v3b of the SDK, available here: https://developers.facebook.com/android