i've a little problem with my code.
I'm trying to perform a volley request on doInBackground behaviour and then to use its result to set some layout elements. Here's the async snippet:
private class MyAsyncTask extends AsyncTask<String, Void, Message>
{
#Override
protected Message doInBackground(String... params) {
rm = new RequestManager(MessageDisplay.this);
idM = params[0];
retrieveMessage(new VolleyCallbackOp(){
public void onSuccess(List<Message> ml) {
m = ml.get(0);
Log.d("print1", m.getContent()); <---- this is fine
}
});
Log.d("print2", m.getContent()); <---- m always null
return m;
}
#Override
protected void onPostExecute(Message m) {
super.onPostExecute(m);
Log.d("messaggio", m.getContent());
mds = new MessageDisplaySetter(MessageDisplay.this);
View v = mds.setMessageDisplayInfo(m, 3);
contentD.addView(v);
}
}
});
}
this code is called in activity onCreate():
Message m = new Message();
String target2 = i.getExtras().getString("messageId");
new MyAsyncTask().execute(target2);
The problem is that the Log "print2" tell the variable m is null while "print1" is ok.
Have you any tip to pass the result of this request to the related onPostExecute()?
The reason why your log for print2 is null - is because you are in a race condition. By calling new VolleyCallbackOp you are doing an asynchrounous network call which might take a while to complete. Your code does not wait until it's finished. That's why print2 is null most of the time.
There are several solutions for your case. One of them is to use the callback mechanism of onSuccess and do your logic there.
Related
I am calling another class's method from doInBackground of async task.
Now i need to stop the download when cancel is called. I am not sure where to check the value of isCancelled().
class myasync extends Asynctask{
protected String doInBackground(String... sURL) {
abc = new abc();
abc.getURLResult(sURL[0])
}
}
class abc()
{
getURLResult(String URL)
{
for(int i=0; i<fp.size(); i++){
//some text to download
}
}
}
class myclass
{
myclass()
{
myasync = new myasync();
myasync.execute("http:\\");
}
stopDownload()
{
myasync.cancel(true);
}
}
EDIT:
Have used the below solution by combining the two answers below:
1. myclass.cancel1(true);
class myclass
{
myclass()
{
myasync = new myasync();
myasync.execute("http:\\");
}
stopDownload()
{
myasync.cancel1(true);
}
}
2.
class myasync extends Asynctask{
protected String doInBackground(String... sURL) {
abc = new abc();
abc.getURLResult(sURL[0])
}
cancel1()
{
abc.cancel();
}
}
3.
class abc()
{
private boolean cancel = false;
getURLResult(String URL)
{
for(int i=0; i<fp.size(); i++){
//some text to download
if(cancel)
break;
}
}
cancel()
{
cancel = true;
}
}
The above method is working. However the methods myclass.stopDownload() is running in UI thread , and hence myasync.cancel1() and abc.cancel() are running the UI thread. And myAsync.doInBackground() and hence abc.getURLResult() are running in seperate thread. I dont know much about inter process communication. I hope this is right thing to do.
Not very nice, but you can do something like this by adding a static variable isDownloading:
protected String doInBackground(String... sURL) {
abc = new abc();
abc.getURLResult(sURL[0])
}
}
class abc()
{
getURLResult(String URL)
{
for(int i=0; i<fp.size(); i++){
if(!myclass.isDownloading){ //ADDED
break; // or Return or handle Cancel
}
//some text to dopwnload
}
}
class myclass
{
public static boolean isDownloading; // ADDED
myclass()
{
myasync = new myasync();
isDownloading = true; // ADDED
myasync.execute("http:\\");
}
stopDownload()
{
isDownloading = false; // ADDED
myclass.cancel(true);
}
}
Update:
From the AsyncTask Cancel doc. we have to check if the async task got cancelled as you say.
Calling this method will result in onCancelled(Object) being invoked
on the UI thread after doInBackground(Object[]) returns. Calling this
method guarantees that onPostExecute(Object) is never invoked. After
invoking this method, you should check the value returned by
isCancelled() periodically from doInBackground(Object[]) to finish the
task as early as possible.
To do that send the asyncTask itself to the getURLResult as parameter along with the URL:
protected String doInBackground(String... sURL) {
new abc().getURLResult("http://...", this); // this here is the asyncTask itself.
}
getURLResult(String URL, myasync myAsyncTask)
{
for(int i=0; i<fp.size(); i++){
if(myAsyncTask.isCancelled()){
break;
}
}
}
Don't use a boolean as other suggested. it's not safe at all since another AsyncTask could be started. and it is a background threads. you can't guarantee which will check the boolean first. could cancel all AsyncTasks.
Old post:
The only place you need to check for cancellation to guarantee the cancellation! is on the onPostExecute. You can't guarantee that the async task got cancelled on calling cancel method. Therefore, you need to check whether the client application asked to cancel it and the returned data is not wanted anymore.
private boolean askedForCancellation = true;
#Override
protected void onPostExecute(Object response) {
if (!askedForCancellation)
// parse response
else
// ignore. or send message to activity to stop loading if you didn't already did that when called cancel method.
}
To achieve that add the following cancel method to the AsyncTask:
public final boolean cancel(boolean mayInterruptIfRunning) {
askedForCancellation = true;
return mFuture.cancel(mayInterruptIfRunning);
}
In your class:
myasync.cancel(true);
myasync = null;
Set myasync to null is ok. because, you can't use it anymore for execution again. you will get a runtime error. you need to re-initialise it.
To check if AsyncTask asked for cancellation. check if the value of
myasync is equal to null. remember the AsyncTask asked to get
cancelled and not cancelled because there is no guarantee that it is
going to be cancelled on calling cancel. What you do is to ignore the
response on onPostExecute
I used this approach in more than 15 applications till now. No bugs and no unexpected behaviours.
I've been working on an android app which regularly checks a mysql database using JSON and everything works fine with my code.
Im having trouble running this as a timer as it only runs once and then stops.
The only code i managed to get working runs the http request on the UI thread which freezes up.
Any help would be most appreciated.
Thank in advance,
#Override
protected void onCreate(Bundle savedInstanceState) {
...
checkUpdate.start();
...
}
private Thread checkUpdate = new Thread() {
public void run() {
try {
// my code here to get web request to return json string
}
String response = httpclient.execute(httppost, responseHandler);
mHandler.post(showUpdate);
}
...
}
private Runnable showUpdate = new Runnable(){
public void run(){
try{
// my code here handles json string as i need it
Toast.makeText(MainActivity.this,"New Job Received...", Toast.LENGTH_LONG).show();
showja();
}
}
}
private void showja(){
Intent i = new Intent(this, JobAward.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
}
As #Raghunandan suggested, the standard way to perform work in the background on Android, and then modify the UI when that work is done, is using AsyncTask.
First define a new subclass of AsyncTask:
private class JsonRequestTask extends AsyncTask<HttpUriRequest, Void, String> {
protected String doInBackground(HttpUriRequest... requests) {
// this code assumes you only make one request at a time, but
// you can easily extend the code to make multiple requests per
// doInBackground() invocation:
HttpUriRequest request = requests[0];
// my code here to get web request to return json string
String response = httpclient.execute(request, responseHandler);
return response;
}
protected void onPostExecute(String jsonResponse) {
// my code here handles json string as i need it
Toast.makeText(MainActivity.this, "New Job Received...", Toast.LENGTH_LONG).show();
showja();
}
}
and then you would use the task like this, instead of your Thread:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
JsonRequestTask task = new JsonRequestTask();
task.execute(httppost);
...
}
You may run the task again by simply creating a new JsonRequestTask() and calling its execute() method.
A common practice for a simple async task like this is to make it a private inner class within the Activity class that uses it (if only one Activity needs it). You may need to change the scope of some of your activity's variables so that the inner class may use them (e.g. move local variables to member variables).
The goal:
Using Google App Engine server and Android client, I'm trying to put on the Google map at the Android client Users overlays. Every 30 seconds I'm polling the server and getting Vector that contains users and adding it to the map.
Current status:
I'm dong all that using in one new thread, So after running the app I got:
weird behaviors(delayed overlays, multiple overlays) and after that crushed with ConcurrentModificationException.
After reading a bit i figured out that I need to work with AsyncTask.
Correct me if I'm wrong,But I understand that everything done in the Activity at at onCreate is "running" in UIhread so I need to put the "Logic" (All the Network handling) in doInBackground and all the UI Handling like putting overlays on the map in onPostExecute.
My Question are:
1) In the current status I'm doing:
new Thread()
{
#Override
public void run()
{
super.run();
while(true)
{
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
putNewOnlineUserOnTheMap();
}
}
}.start();
What is the right way to convert this To AsyncTask?
Do I poll the server still using new thread in the doInBackground or there is right way to do this?
2) Is there a specific list of what counts as UI to put in onPostExecute or any concepts list?
In my case I guess that in need to put putNewOnlineUserOnTheMap() in onPostExecute.
Thanks.
Something similar to the following:
class UpdateTask extends AsyncTask<Void, Vector, Void>{
#Override
protected Void doInBackground(Void... params) {
// this is running in a background thread.
while (!isCancelled()) {
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
// send the result back to the UI thread
// onProgressUpdate will be called then
publishProgress(responseFromServer);
}
return null;
}
#Override
protected void onProgressUpdate(Vector... values) {
// this is executed on the UI thread where we can safely touch UI stuff
putNewOnlineUserOnTheMap(values[0]);
}
}
You can't use the result of the task since the task is finished then. But you can use the progress publishing mechanism to get periodic results. If you use it like that and do the modification on the UI thread you should not get ConcurrentModificationException because you do the modifications on the one thread that can safely modify the UI.
One thing to note here: create new instances of your Vector in the background thread and then use it to update the UI. But don't touch the same object afterwards in the backgroundthread. That way you don't need any synchronization since after the background thread sends it away it is only the UI thread that touches it. (and you could use a simple ArrayList instead of a Vector)
AsyncTask uses generics and varargs.The parameters that are passed to the asyntask are . TypeOfVariableArgumentsParameters is passed into the doInBackground(), ProgressParam is used for progress information and ResultParam must be returned from doInBackground() and is passed to onPostExecute() as parameter.
example:--
protected class ParsingTask extends AsyncTask> {
private ProgressDialog loadingDialog = new ProgressDialog(JsonParserActivity.this);
protected void onPreExecute() {
loadingDialog.setMessage("loading app store..");
loadingDialog.show();
}
#Override
protected ArrayList<Items> doInBackground( Context... params ) {
// do ur process here.
return result;
}
if (!this.isCancelled()) {
}
return result;
}
#Override
protected void onProgressUpdate(String... s) {
super.onProgressUpdate(s);
Toast.makeText(getApplicationContext(), s[0], Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute( ArrayList<Items> response ) {
//if u r dealing with list view and adapters set the adapter here at the onPostExecute()
loadingDialog.dismiss();
}
#Override
protected void onCancelled() {
super.onCancelled();
Toast.makeText(getApplicationContext(), "The operation was cancelled", 1).show();
}
}
You can use AsyncTask like below. Hope this will help you..
Class YourClass{
void YourClass(){
NetworkTask nT = new NetworkTasK();
nT.execute();
}
}
protected class NetworkTask extends AsyncTask<Void, String, Boolean>
{
#Override
protected Boolean doInBackground(Void... params)
{
try
{
String response;
while(keepreceiving)
{
response = in.readLine();//Prog Counter stops here until getting i/p.
if(response != null)
yourFunctionForResponse(response);
}
}
catch (Exception ex)
{
}
return null;
}
private void yourFunctionForResponse(String response){
//things to do....
}
}
You may also try runOnUiThread(Runnable action) along with this to implement your work.
I have some problem with Android AsyncTask. There is an Activity which contains some TextView a button and a picture. When an user entered this activity I start an asynctask to check whether the user can go toward from the activity (until the task not finish the button not active). Then I want to start another asyntask to get the picture.
So I made an inner class:
AsyncTask<String, Void, JSONObject>() authTask = new AsyncTask<String, Void, JSONObject>() {
#Override
protected JSONObject doInBackground(String... params) {
//call the rest api
}
#Override
protected void onPostExecute(JSONObject result) {
// check the result
// and make another asynctask
AsyncTask<String, Void, Bitmap> imageTask = new Async.... {
// get image
}
imageTask.execute();
}
}
and I call
authTask.execute(); from the UI thread.
I have a bad feeling about this, especially it seems doesn't work (it's ok few times but suddenly it "freeze": no exception just hanging and the progress bar is spinning. Nothing happens and the button won't be active.)
There is another way to get an information and when it's finished immediately start another task?
UDPATE:
I working with api level 10. In authTask I get some information which is needed to start imageTask (some id) so I have to call these tasks in a row. In api level 10 it's is possible?
Thanks in advance!
Br, Peter
you can use getStatus() checks whether the the AsyncTask is pending, running, or finished.and when finsh start your new task.like:
if(authTask .getStatus() == AsyncTask.Status.PENDING){
// My AsyncTask has not started yet
}
if(authTask .getStatus() == AsyncTask.Status.RUNNING){
// My AsyncTask is currently doing work in doInBackground()
}
if(authTask .getStatus() == AsyncTask.Status.FINISHED){
// START NEW TASK HERE
}
example for your app:
btn.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
if (authTask != null && authTask.getStatus() == AsyncTask.Status.FINISHED) {
//START YOUR NEW TASK HERE
}
else
{
//IGNORE BUTTON CLICK
}
}
});
1:
You could write the code for authTask and then for imageTask, one after the other, within a single doInBackground(). This single AsyncTask instance would be fire by a single execute() statement. This may or may not be practical depending on needed UI interactions.
2:
Edit: as noted by kabuku this information is mostly for HoneyComb+. Pre HoneyComb I would definitely go with option 1 above. executeOnExecutor() is api level 11+
In receent versions, execute() will send your AsyncTasks in series by default (ICS+). If you want to make sure this happens, specify the serial executor.
In your case this would be:
authTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
// Image task will only be done AFTER textViewTask is done
imageTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
And for newer versions a simple
...
// ICS+ and pre honeycomb (I think)
authTask.execute();
// Image task will only be done AFTER textViewTask is done
imageTask.execute();
...
From the AsycnTask.execute() documentation:
Note: this function schedules the task on a queue for a single
background thread or pool of threads depending on the platform
version. When first introduced, AsyncTasks were executed serially on a
single background thread. Starting with DONUT, this was changed to a
pool of threads allowing multiple tasks to operate in parallel. After
HONEYCOMB, it is planned to change this back to a single thread to
avoid common application errors caused by parallel execution.
PS:
To run tasks independent of each other you must use the AsyncTask.THREAD_POOL_EXECUTOR. That requires a different executor:
// Go parallel! (NOT what you want)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Its not a good design to nest AsyncTask. Do all the heavy lifting in doInBackground and simply post/update the results. In other words, combine the processing of second AsyncTask in your first one.
From the code that you showed it does not seem to make sense to spawn second task. Just get you image inside doInBackground of the first task right after authorization.
If you need to update UI in between, you can do it in progress update.
int count;
private void attemptConnect()
{
count = 0;
str_lang = "English";
str_wait = "Plaese Wait";
new AllQuestion().execute();
}
private class AllQuestion extends AsyncTask<String, String, String> {
ProgressDialog pg;
#Override
protected void onPreExecute() {
super.onPreExecute();
pg = new ProgressDialog(LanguageActivity.this);
pg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pg.setMessage(str_wait);
pg.setCancelable(false);
pg.show();
}
#Override
protected String doInBackground(String... strings) {
try {
SoapObject soapObject = new SoapObject(AppConstant.NAMESPACE, AppConstant.QUESTION_SOAP_METHOD);
soapObject.addProperty("language", str_lang);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(soapObject);
HttpTransportSE se = new HttpTransportSE(AppConstant.webUrl);
se.call(AppConstant.QUESTION_SOAP_ACTION, envelope);
Object responce = envelope.getResponse();
Log.d("Question List:=>>", "" + responce);
return responce.toString();
} catch (Exception e) {
e.printStackTrace();
pg.dismiss();
return null;
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (pg.isShowing()) {
pg.dismiss();
Log.i(TAG, s);
if (s != null || !s.equalsIgnoreCase("")) {
try {
JSONArray array = new JSONArray(s);
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
String queId = obj.getString(TAG_QID);
String que = obj.getString(TAG_QUE);
String str_Opt = obj.getString(TAG_OPT);
question = new Question(queId, que, str_lang, str_catId, str_Opt, manager.getDateTime());
helper.insertQuestion(question);
}
count++;
if (count < 5) {
if (count == 1) {
str_lang = "German";
str_wait = "bitte warte einen Moment";
new AllQuestion().execute();
}
if (count == 2) {
str_lang = "Italian";
str_wait = "per favore aspetta un momento";
new AllQuestion().execute();
}
if (count == 3) {
str_lang = "Chinese";
str_wait = "请稍候";
new AllQuestion().execute();
}
if (count == 4) {
str_lang = "French";
str_wait = "patientez s'il-vous-plait";
new AllQuestion().execute();
}
Log.d("All Question:-", question.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}
I have an idea to make async series in just one async task:
protected Boolean doInBackground(String... params) {
if(params[0] == "taskA") {
//do somthing
params[0] = "taskB";
}
if(params[0] == "taskB") {
//do somthing
params[0] = "taskC";
}
if(params[0] == "taskC") {
//do somthing
params[0] = "taskD";
}
if(params[0] == "taskD") {
//do somthing
return true;
}
And in your main thread just call async task like this:
ShowMyProgress(); //if you like
new MyAsyncTask().execute("taskA");
And finally you can hide your progress on onPostExecute like:
protected void onPostExecute(final Boolean success) {
if (success) {
....
HideMyProgress();
}
}
I have solved this kind of problem when i had to download something from a database before login in the user into the app, with this i fixed this problem.
To use ObservableInteger you can do this
first declare it
private ObservableInteger mObsInt;
then in your onCreate you will have a listener waiting for the values of the mObsInt to change, after those values change you can do anything you want
//Listener
mObsInt = new ObservableInteger();
mObsInt.set(0);
mObsInt.setOnIntegerChangeListener(new OnIntegerChangeListener()
{
#Override
public void onIntegerChanged(int newValue)
{
if (mObsInt.get()==1)
//Do something if the first asyncTask finishes
if (mObsInt.get()==2){
//Do something if the second asyncTask finishes, in this case i just go to another activity when both asyncTasks finish
Intent mainIntent = new Intent().setClass(LoginActivity.this, Principal.class);
startActivity(mainIntent);
finish();
}
}
});
So, how it works
ObservableInteger will be looking for changes in the variable mObsInt, so lets say if mObsInt is equal to 1 it will do something, if is equal to 2 will do another thing, so, to solve this problem with 2 asynctasks is easy, when one of the asynctasks finishes mObsInt will be equal to 1 , if the other asyncTask finishes so mObsInt will be mObsInt++ , and then your mObsInt will be equal to 2, the listener will be waiting for the values, and then do what you want to do when the values match your if statment at the onCreate method
now, just in your asynctasks just put in your onPostExecute() method this line
mObsInt.set(mObsInt.get()+1);
so if the first async finish, mObsint == 1 , if the second finish mObsInt == 2, and then you handle what you want to do in your onCreate method
hope this helps for you, it helped me
You can get more info at this doc : https://developer.android.com/reference/android/databinding/ObservableInt.html
happy coding !
I am new to Android programming and Threads. I want to get a picture from a remote Server and display it. (that works so far ^^)
But the picture is from a camera and so I need a new one as soon as I show the one I downloaded before. That means ,that the Thread should never stop grabbing the picture. (As long the Activity exists.)
Also I just want to establish 1 connection to the server and then just do HTTP-gets. So I have to have an parameter "connection" that the Thread can use.
To get an idea - it should work something like this (but obviously it does not):
private class DownloadImageTask extends AsyncTask<URLConnection, Void, Bitmap> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
private URLConnection connection = null;
protected Bitmap doInBackground(URLConnection...connection ) {
this.connection = connection[0];
return getImageFromServer(connection[0]);
}
protected void onPostExecute(Bitmap result) {
pic.setImageBitmap(result);
this.doInBackground(connection);
}
}
Might be better to use a Thread here since AsyncTask is for when the Task ends at some point. Something like below could work for you. Apart from that you could be better off using a local Service
protected volatile boolean keepRunning = true;
private Runnable r = new Runnable() {
public void run() {
// methods are a bit bogus but it should you give an idea.
UrlConnection c = createNewUrlConnection();
while (keepRunning) {
Bitmap result = getImageFromServer(c);
// that probably needs to be wrapped in runOnUiThread()
pic.setImageBitmap(result);
}
c.close();
}
};
private Thread t = null;
onResume() {
keepRunning = true;
t = new Thread(r);
t.start();
}
onPause() {
keepRunning = false;
t = null;
}
You should set some delay for it, but to fix this I think that it should look like this:
private class DownloadImageTask extends AsyncTask<URLConnection, Void, Bitmap> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
private URLConnection connection = null;
protected Bitmap doInBackground(URLConnection...connection ) {
this.connection = connection[0];
return getImageFromServer(connection[0]);
}
protected void onPostExecute(Bitmap result) {
pic.setImageBitmap(result);
this.execute("...");
}
}
Async Task can only be executed once...
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
see this.. documentation on AsyncTask documentation on AsyncTask
I suggest it is better if you use a service to download...
or even a thread can be used...
like this
public void run() {
while (true) {
//get image...
}
}