In my android project I use many AsynTask in one activity. I need to stop one AsynTask when I start other.
I'm using myAsynTask.cancel(true); in my android project. But it does stop the AsynTask.
protected String doInBackground(String... args) {
HashMap<String, String> params = new HashMap<>();
params.put("id", args[0]);
Log.d("get value: ", params.toString());
JSONObject json = jParser.makeHttpRequest(url_comment, "GET", params);
Log.d("All matches: ", json.toString());
if(isCancelled()) {
finish();
}
else {
try {
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {
JSONmatches = json.getJSONArray(TAG_vedio);
for (int i = 0; i < JSONmatches.length(); i++) {
JSONObject c = JSONmatches.getJSONObject(i);
String title = c.getString(TAG_title);
String url = c.getString(TAG_url);
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_title, title);
map.put(TAG_url, url);
arrayList22.add(map);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
You actively have to check for isCancelled while executing your loop in doInBackground.
You should break the loop if isCanceled is true.
From the official Android documentation:
A task can be cancelled at any time by invoking cancel(boolean).
Invoking this method will cause subsequent calls to isCancelled() to
return true. After invoking this method, onCancelled(Object), instead
of onPostExecute(Object) will be invoked after
doInBackground(Object[]) returns. To ensure that a task is cancelled
as quickly as possible, you should always check the return value of
isCancelled() periodically from doInBackground(Object[]), if
possible (inside a loop for instance.)
Related
I am trying to get the id numbers of foods from the USDA database. My issue is that I can get the JSON data, but I can not take it out of the OnPostCreate() function. When I iterate through JSONdataWIthIDs in the OnPostCreate() all the data is there. But when I try to use the data someplace else, it is empty. How do I store the data into an array?
Here is the constructor.
public USDA(String nameOfFoodToSearchFor) {
setJSONdataWIthIDs(nameOfFoodToSearchFor);
// This returns 0
Log.i("TAG", "SONdataWIthIDs size: " + JSONdataWIthIDs.size());
// This does not work.
for(String s: JSONdataWIthIDs)
{
Log.i("TAG OUTPUT", s);
}
}
Here is the code with the OnPostCreate.
private void setJSONdataWIthIDs(String nameOfFood) {
final String url1 = "https://api.nal.usda.gov/ndb/search/?format=json&q=" + nameOfFood + "&sort=n&max=25&offset=0&api_key=x5qM9v8PkjZrTf2cVSHzoK7y4GsSBgoQEmJsbwqV";
AsyncTask asyncTask = new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url1)
.build();
Response response = null;
try {
response = client.newCall(request).execute();
return response.body().string();
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Object o) {
String lines[] = o.toString().split("\\r?\\n");
for(int i = 0; i < lines.length; i++)
{
JSONdataWIthIDs.add(lines[i]);
}
// This works
for(String s : JSONdataWIthIDs)
{
Log.i("TAG", s);
}
}
}.execute();
}
The problem is quite simple. The Log.i("TAG", "SONdataWIthIDs size: " + JSONdataWIthIDs.size()); statement is executed before the onPostExecute(). So the JSONdataWIthIDs is empty.
The call to async task is done asynchronously (doInBackground()). And you are saving the value to JSONdataWIthIDs in onPostExecute(). So you can access the id's only after the async task is done.
How do I store the data into an array?
The data is already stored into the array in onPostExecute(). The only problem is that you can access it only after the onPostExecute() is called.
onPostExecute is where the execution flow comes back from the worker thread (that is what supports AsyncTask) to the UI thread. Your log line,
Log.i("TAG", "SONdataWIthIDs size: " + JSONdataWIthIDs.size());
happens in the UI thread and is running in parallel with the working thread at that moment. So the result is not available.
I'm writing a android chat application with socket.io-client-java.I want to check whether the client user exist at first.So I need to send a command like "user/exist" to server url and get the response from server.I need to wait the server response then can go to next step.But the socket.io use the asynchronous callback.For getting the response synchronous I known the Furture and Callable only.So I tried the way using code as below:
//this is request method using socket.io
public JSONObject request(final String method,final String url,final JSONObject data){
final JSONObject responseObj = new JSONObject();
if (mSocket.connected()) {
mSocket.emit(method, reqObj, new Ack() {
#Override
public void call(Object... objects) {
System.out.println("get Ack");
try {
responseObj.put("body", (JSONObject) objects[0]);
}catch (JSONException e){
e.printStackTrace();
}
}
})
}
}
//this is Callable call implement
#Override
public JSONObject call(){
return request("get","https://my-chat-server/user/exist",new JSONObject());
}
//this is call method in activity
ExecutorService executor = Executors.newCachedThreadPool();
Future<JSONObject> response = executor.submit(mApiSocket);
executor.shutdown();
JSONObject respObj = new JSONObject();
JSONObject respBody = new JSONObject();
try {
respObj = response.get();
respBody = respObj.getJSONObject("body");
}catch (ExecutionException e){
}catch(InterruptedException e1){
}catch(JSONException e2){
}
But it dose not work.The respObj is null.
How can i get the reponse synchronous?
I am a green hand on java and forgive my poor chinese english.
Any help would be appreciated!
I known the js can use Promise and await like below:
//request method
static request(method, url, data) {
return new Promise((resolve, reject) => {
this.socket.emit(method,
{
url: url,
method,
data,
},
async (res) => {
if (res.statusCode == 100) {
resolve(res.body, res);
} else {
throw new Error(`${res.statusCode} error: ${res.body}`);
reject(res.body, res);
}
}
)
})
}
//call method
response = await mSocket.request('get','https://my-chat-server/user/exist', {
first_name: 'xu',
last_name: 'zhitong',
});
I'm not sure this is the best way but we can wait for the callback as follows:
#Nullable
Object[] emitAndWaitForAck(#NotNull String event, #Nullable Object[] args,
long timeoutMillis) {
Object[][] response = new Object[1][1];
Semaphore lock = new Semaphore(0);
socketClient.emit(event, args, ackArgs -> {
response[0] = ackArgs;
lock.release();
});
try {
boolean acquired = lock.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS);
if (acquired) {
return response[0];
}
} catch (InterruptedException ignored) {
}
return null;
}
Assuming your socket.io server returns one argument containing the body (or null) you would call it something like this:
String method = "get";
String url = "https://my-chat-server/user/exist";
long timeoutMillis = 5000;
Object[] args = emitAndWaitForAck(method, new String[]{url}, timeoutMillis);
JSONObject response = (JSONObject) args[0];
The task is simple, but I want to do it in the right way and I would love to hear your expert advice because I am novice in android developing.
First the application is just for me so I really don't care about security and stuff.
So my objective is like this:
I have a large amount of data that I want to transfer to my MYSQL database, the easiest way for me is to use HTTP POST method, but I am concerned about the part that the application may get stuck or some data won't pass because of the many POST requests that are gonna be.
So how exactly should I pass the data using POST request with insuring that all of the requests will be sent one by one without skipping any or losing data ?
Just the logic behind this would be enough I don't really need the code part.
Hopefully I was clear enough.
Retrofit FTW. Makes networking easy on Android (RESTful) and it include Gson.
Speaking of Gson... You mention you might be making many POSTs? If so, you should probably convert your data to JSON instead, and send it over the network that way. Google's Gson is a fantastic way to easily convert a Java object to JSON.
http://square.github.io/retrofit/
https://github.com/google/gson
Before reading: this is my way for implementing posts and gets, this is not the best way ever, but just the best way for my needs, feel free to edit/not use/implement it yourself
I personally prefer OkHTTP library, it is easy to use and easy to implement.
Implementation is really easy, just add this row in your Gradle app-level
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
Then I created an helper class for get and post calls (I don't need many configurations, so a static one for me was enough, if you need more stuff you can easily implement. Also the timeouts are set for my needs and you can chenge them freely)
private String ConsumeGetRequest(String path) {
int tries = 0;
boolean isMyException = true;
while (tries <= 3 && isMyException) {
try {
isMyException = false;
tries++;
Response response = executeRequestBody(path, null);
if (response != null && response.body() != null)
return response.body().string();
else
return "";
} catch (ConnectException e) {
e.printStackTrace();
if (e.getMessage().contains("Failed to connect to") && tries <= 3) {
isMyException = true;
}
} catch (Exception ex) {
ex.printStackTrace();
return "";
}
}
return "";
}
private Pair<Boolean, String> ConsumePostRequest(String path, String postData) {
int tries = 0;
String errorMsg = null;
boolean isMyException = true;
//you can ignore this while, it was for our internal reasons and it's just a check.
while (tries <= 3 && isMyException) {
try {
isMyException = false;
tries++;
Response response = executeRequestBody(path, postData);
if (response != null && response.body() != null)
return new Pair<>(response.isSuccessful(), response.body().string());
else
return new Pair<>(false, null);
} catch (ConnectException e) {
errorMsg = e.getMessage();
if (e.getMessage().contains("Failed to connect to") && tries <= 3) {
isMyException = true;
}
} catch (Exception ex) {
errorMsg = ex.getMessage();
}
}
return new Pair<>(false, errorMsg);
}
private Response executeRequestBody(String path, String postData) throws IOException {
String url = String.format("%s%s/", RuntimeHelper._baseWebServiceIP, path);
if (okHttpClient == null) {
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.build();
}
Request.Builder builder = new Request.Builder().url(url);
if (postData != null && !postData.isEmpty()) {
RequestBody body = RequestBody.create(RuntimeHelper._okHttpTypeJson, postData);
builder = builder.post(body);
}
Request request = builder.build();
return okHttpClient.newCall(request).execute();
}
with those two methods (a couple of examples) I create my path and I call the proper method for my needs.
//Post
public boolean setAlerts(String postData) {
String path = String.format("api/wfm/v1/set-alerts/%s/%s", authToken, resourceId);
return ConsumePostRequest(path, postData).first;
}
//Post
public String isAlertUpdated(String lastDownloadDate) {
String path = String.format("api/wfm/v1/is-alert-updated/%s/%s", authToken, lastDownloadDate);
return ConsumeGetRequest(path);
}
Then with an AsyncTask you can perform the operation without blocking UI
public class NewAlertAsyncTask extends AsyncTask<String, String, Boolean> {
Context context;
private WebApiMethodsController webApiMethodsController;
AuthenticatedUser authenticatedUser;
public NewAlertAsyncTask(Context ctx) {
this.context = ctx;
authenticatedUser = AuthenticatedUser.getIstance(context);
webApiMethodsController = new WebApiMethodsController(authenticatedUser.getAuthenticationTokenID().toString(), authenticatedUser.getResourceID().toString(), context);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values) {
}
#Override
protected Boolean doInBackground(String... datas) {
Boolean result;
try {
result = webApiMethodsController.setAlerts(datas[0]);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return result;
}
#Override
protected void onPostExecute(Boolean s) {
if(s){
//manage succes, I use this
mCallback.onNewAlertCreated();
}
else{
//manage error
}
}
}
mine is a really simple structure, you can implement it with callbacks, status progress, deeper return status check, ...
You can simply call the asynctask with this
NewAlertAsyncTask newAlertAsyncTask = new NewAlertAsyncTask(getActivity());
newAlertAsyncTask.execute(gson.toJson(alertList));
Here is my Code:
public class ServerCall {
Context context;
public int cartCount;
public ServerCall(Context context){
this.context=context;
}
public Integer addCartItem(RequestObject requestObject) {
new AddToCartList().execute(requestObject);
Log.d("count",String.valueOf(cartCount));
return cartCount;
}
public class AddToCartList extends AsyncTask<RequestObject, Void, JSONObject> {
#Override
protected JSONObject doInBackground(RequestObject... arg0) {
// Creating service handler class instance
ServiceHandler sh = new ServiceHandler();
// Making a request to url and getting response
String jsonStr = sh.makeServiceCall(arg0[0], ServiceHandler.POST);
// List<Products> result = new ArrayList<Products>();
Log.d("Response: ", "> " + jsonStr);
JSONObject product = new JSONObject();
if (jsonStr != null) {
try {
JSONObject jsonObj = new JSONObject(jsonStr);
product = jsonObj.getJSONObject("rsBody");
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("ServiceHandler", "Couldn't get any data from the url");
}
return product;
}
#Override
protected void onPostExecute(JSONObject result) {
super.onPostExecute(result);
try {
if (result != null) {
String status = result.getString("status");
int totalCartItem = result.getInt("totalCartItem");
/* cartHelper = new CartHelper();
cartHelper.setStatus(status);
cartHelper.setTotalCartItem(totalCartItem);*/
cartCount=totalCartItem;
Log.d("status",status);
Log.d("totalCartItem",String.valueOf(cartCount));
Toast.makeText(context, status, Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
return;
}
}
}
We didn't get value of global variable cartCount which I set inside AddToCartList class and try to get its value from addCartItem() function from where AddToCartList is called but we get null value.
I think that the main problem in your solution is the fact that you're trying to edit ServerCall variable from an Inner class, this would work only if cartCount is static, and I suggest you wait for your task to be finished as some people have already mentioned, using the get method new AddToCartList().execute().get()
The problem is, ServerCall and AddToCartList are not the same class, so you must first get a reference to the servercall in addtocartlit, then reference the cartCount using your reference to the servercall instance, like call.cartCount, instead of cartcount, unless its an inner class which it does not appear to be.
Secondly, you must save a reference to the addtocartlist asynctask inside addCartItem() ,then call its .get() method after starting it, this will ensure it finishes before you try to log the new value.
I have a native android app using volley framework to fetch data from a PHP server end script.
It worked well on most time, but I have 20% percentage failure.
The error says:
com.android.volley.NoConnection, java.io.InterruptedIOException.
I debugged that I found the statuscode = 0, which obviously was wrong.
I have no idea what can be the reason? Since it is working most time so there should be no obvious error code.
FYI, those PHP script on the server end works very well for my IOS app.
Please allow me post my code here:
retryConnBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
txtOut.append("\n");
txtOut.append("Button with Retry Click");
Log.d("Click", "Button Click");
final String url = "https://www.myserver.com/api/getBalanceInfoTest?token=7ff3317a4f3dc07d0c297a7d16d2049c&t=" + System.currentTimeMillis();
//final String url = "http://192.168.1.23/base/test/";
JsonObjectRequest getRequest = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
txtOut.append("\n");
txtOut.append("Result with Retry:");
txtOut.append(response.toString());
Log.d("Response", response.toString());
VolleyLog.e("Response:", response.toString());
}
},
new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError error) {
txtOut.append("\n");
txtOut.append("Error with Retry:");
txtOut.append(error.toString());
Log.d("Error.Response", error.toString());
VolleyLog.e("Error:", error.getMessage());
}
});
getRequest.setRetryPolicy(new DefaultRetryPolicy(5000, 5, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
queue.add(getRequest);
queue.start();
}
});
}
And for more information, the output of my PHP script is:
{"hsaBalance":"1000.00"}, created by Json_encode() function of PHP.
I have fixed this bug.
It is not a network issue.
queue.add(getRequest);
queue.start();
should be
queue.add(getRequest);
So the key is we should remove queue.start().
Michael Cheng is right,because volley had start the RequestQueue when we call newRequestQueue as below:
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
and when we call start, volley will call stop to “make sure any currently running dispatchers are stopped”,in stop method volley does this below:
public void stop() {
if (mCacheDispatcher != null) {
mCacheDispatcher.quit();
}
for (int i = 0; i < mDispatchers.length; i++) {
if (mDispatchers[i] != null) {
mDispatchers[i].quit();
}
}
}
and the quit method does this below:
public void quit() {
mQuit = true;
interrupt();
}
maybe you can see the reason,why interrupted.
More, interrupt method does this below:
public void interrupt() {
// Interrupt this thread before running actions so that other
// threads that observe the interrupt as a result of an action
// will see that this thread is in the interrupted state.
nativeInterrupt();
synchronized (interruptActions) {
for (int i = interruptActions.size() - 1; i >= 0; i--) {
interruptActions.get(i).run();
}
}
}
the reason maybe this as metioned above:
Interrupt this thread before running actions so that other threads that observe the interrupt as a result of an action will see that this thread is in the interrupted state.
You are having sometimes problems with your connection. Look at InterruptedIOException API:
InterruptedIOException Signals that an I/O operation has been interrupted. An InterruptedIOException is thrown to indicate that an input or output transfer has been terminated because the thread performing it was interrupted.
so only you can do is to catch the possible exceptions occuring when converting JSon and having a workaround for this.
// rest of your code...
final String url = "https://www.myserver.com/api/getBalanceInfoTest?token=7ff3317a4f3dc07d0c297a7d16d2049c&t=" + System.currentTimeMillis();
try {
JsonObjectRequest getRequest = new JsonObjectRequest(Request.Method.GET, url, null,
// rest of your code...
queue.add(getRequest);
queue.start();
} catch (InterruptedIOException e) {
// do something when fail print error, show a toast
System.out.err("Error, connection interrupted" + e.getMessage());
Toast.makeText(getApplicationContext(), "press button again", Toast.LENGTH_LONG).show();
}