AsyncTask - after execution, how to update view? - android

In the onCreate() event of an Activity, I have started an AsyncTask to retrieve Product data from a database. After this has been completed successfully, how can I update the display?
Metacode:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.venueviewbasic);
(..)
new GetProductDetails().execute();
class GetProductDetails extends AsyncTask<String, String, String> {
protected String doInBackground(String... params) {
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
// Check for success tag
int success;
try {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("id", vid));
(.. retrieve and parse data and set new textview contents ..)
The textviews etc. don't get updated however.

If you want to update the view from async after complete process in then
you can use
protected void onPostExecute(String result)
{
textView.setText(result);
}
But if you want to update data while running background process then use.
For ex...
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));<------
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) { <-------
setProgressPercent(progress[0]);
}
for more detail see this link
Hope this will help you...!

I am guessing the question is more about how to get hold of the UI View if the asyncTask is in a separate file .
In that case you have to pass the context to the Async task and use that to get the view.
class MyAsyncTask extends AsyncTask<URL, Integer, Long> {
Activity mActivity;
public MyAsyncTask(Activity activity) {
mActivity = ativity;
}
And then in your onPostExecute use
int id = mActivity.findViewById(...);
Remember you cannot update the View from "doInBackground" since its not the UI thread.

In your AsyncTask class, add a onPostExecute method. This method executes on the UI thread and can update any UI component.
class GetProductDetails extends AsyncTask<...>
{
...
private TextView textView;
...
protected void onPostExecute(String result)
{
textView.setText(result);
}
}
(The result parameter is the value returned from the doInBackground method of your class.)

Related

Why doesn't AsyncTask executes when the execute method is called using an instance but without the instance works fine? [duplicate]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I don't want to pass any arguments to doInBackground method of the AsyncTask.
So what should be the code like?
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
public class AsyncExample extends Activity{
private String url="http://www.google.co.in";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
new AsyncCaller().execute();
}
private class AsyncCaller extends AsyncTask<Void, Void, Void>
{
ProgressDialog pdLoading = new ProgressDialog(AsyncExample.this);
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method will be running on UI thread
pdLoading.setMessage("\tLoading...");
pdLoading.show();
}
#Override
protected Void doInBackground(Void... params) {
//this method will be running on background thread so don't update UI frome here
//do your long running http tasks here,you dont want to pass argument and u can access the parent class' variable url over here
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
//this method will be running on UI thread
pdLoading.dismiss();
}
}
}
According to AsyncTask, its
AsyncTask<Params, Progress, Result>
Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the
background computation.
Result, the type of the result of the background computation.
So if you want to pass void in doInBackground just pass void in place of Params.
Example code:
class DownloadLink extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
//Do Your stuff here..
return null;
}
}
And call it as:
new DownloadLink().execute();
Create your AsyncTask class as if you don't want to pass any parameter to doInBackground :
public class LongOperation extends AsyncTask<Void, Void, String> {
public LongOperation(Context context) {
}
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(Void... params) {
return null;
}
#Override
protected void onPostExecute(String result) {
}
}
and start AsyncTask as without passing any parameter to execute :
LongOperation longOperation = new LongOperation(this);
longOperation.execute();
Why don't you want to pass any arguments to it? You should explain...
This is how it usually works (example):
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
And to execute it you call:
new DownloadFilesTask().execute(url1, url2, url3);
Source: Android docs

ListView Adapter item Asynktask Stop Issue

I have activity with listview and custom listadapter. EveryItem of List starting a AsyncTask request. Now when i click onback it finish the activity but asynctask isn't finishing. How to finish this all AsyncTask ?
public class MyListAdapter extends ArrayAdapter<String>
{
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
......
if(!status.get(position).isFetch)
{
statusList.get(position).FetchingData=true;
GetRequest request=new GetRequest();
request.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, id);
}
.....
}
class GetRequest extends AsyncTask<String, String, String>
{......}
}
if i pressed backbutton before completing all item task then its finishing activity but not task. How to stop asynctask as activity finish..
You should stop all the tasks manually. Activity lifecycle won't take care of your tasks automatically.
You should manage all the tasks in somewhere(I suggest Activity or Fragment, not in ListView). Gather all the tasks in list and stop'em on onDestroy(or onPause depending your situation).
public MyActivity extends Activity {
private ArrayList<SomeTask> mTasks;
private void startTasks() {
SomeTask task = new SomeTask();
task.execute();
mTasks.add(task);
}
#Override void onDestroy() {
for (SomeTask task : mTasks) {
tasks.cancel(true);
}
}
private class SomeTask extends AsyncTask<Void, Void, Void> {
private MyListItem mItem;
private int mIndex;
public SomeTask(MyListItem item, int index) {
mItem = item;
mIndex = index;
}
protected Long doInBackground(Void... urls) {
// do whatever you want
return null;
}
protected void onPostExecute(Void result) {
// update your adapter here
}
}
}
Sadly, AsyncTask won't just stop even if you call task.cancel(true).
You also have to check if the task is cancelled inside the AsyncTask.
Below is a sample taken from AsyncTask reference page:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
Checkout Cancelling a task section for more information.

AsyncTask cannot update progress when slowly creating an object in background

I know how to use AsyncTask to download file, create a zip file or so.. as I call publishProgress() in my loop.
I got stuck when doInBackground() has a single slow line, no loops here, just creating an object where its constructor has slow loops.
I'm not sure about the reasonable way of updating progress in such case.
Here's a sample code:
public class Session {
private QQActivity activity;
public int createdParts;
public DailyClass daily;
private void checkDaily() {
if(!isDailyReady){
new SetAsyncQQDaily().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
class SetAsyncQQDaily extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
String sdq = null;
daily = new DailyClass(Session.this); //Very very Slow!
// Do other network http
sdq = new String(Base64.encode(bos.toByteArray(),Base64.DEFAULT));
// Do some work
return sdq;
}
#Override
protected void onPostExecute(String sdq) {
//Never mind
}
#Override
protected void onPreExecute() {
Toast.makeText(activity,"Preparing the daily. Get ready!",Toast.LENGTH_LONG).show();
}
#Override
protected void onProgressUpdate(Void... values) {
//TODO: Update Value of leftBar
activity.leftBar.setProgress((100*createdParts)/Utils.DAILY_PART_COUNT);
}
}
}
In the slow constructor class, I can set-back an integer of the current progress: createdParts, but cannot call publishProgress.
public class DailyClass implements Serializable {
public DailyClass(Session session){
for(int i=1;i<=partCount;i++ ){ //Very slow loop
session.createdParts = i; //TODO: reflect value to progress bar!?
for(int j=0;j<questionsCount;j++){
objects[i-1][j] = createDefined(i);
}
Log.d("Daily","created part"+i);
}
}
//Bla .. !
}
I also though of passing the object of the AsyncTask to the slow constructor in order to call publishProgress() from there, but cannot. As publishProgress() is accessible only from doInBackground()
What's the best practice?

How to load EditText fields with data fetched from server

I've got an Activity where before showing the Text/EditText fields, I want to make a call to the server to get the details and then setText of the fields based on the data gotten back from the server.
Below is what I'm doing but the fields don't seem to have the data fetched from the server. I think because I am calling an AsyncTask which gets run in the background and in the mean time the fields are shown to the user.
Question
How does android deal with this? What pattern should I be using?
This activity gets called from MainActivity.java like so:
Intent act = new Intent(getApplicationContext(), MySecondActivity.class);
create.putExtra("theId", "138");
startActivity(create);
in MySecondActivity.java i do the following:
public class MySecondActivity extends SherlockActivity {
private EditText fieldOne;
private EditText fieldTwo;
private MyObj obj = new MyObj();
private int id;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.shared_activity);
fieldOne = (EditText)findViewById(R.id.field_one);
fieldTwo = (EditText)findViewById(R.id.field_two);
id = Integer.parseInt(getIntent().getStringExtra("theId"));
new FetchDetail().execute();
//If I put the below two lines inside the AsyncTask then I get an error:
//"Only the original thread that created a view hierarchy can touch its views."
fieldOne.setText(obj.getOne()); //
fieldTwo.setText(obj.getTwo()); //
}
class FetchDetail extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... strings) {
final RestAdapter restAdapter = new
RestAdapter.Builder().setServer("http://10.0.2.2:8080").build();
final MyTaskService apiManager = restAdapter.create(MyTaskService.class);
final MyObj obj = apiManager.getDetails(id);
return null;
}
}
}
If I put the below two lines inside the AsyncTask then I get an error
Have these in onPostExcute
fieldOne.setText(obj.getOne());
fieldTwo.setText(obj.getTwo());
Do your background computation in doInbackground. Return result in doInbackground. The result of doInbackground computation is a pram to onPostExecute.
So you can update ui in onPostExecute which is invoked on the ui thread
Example:
protected String doInBackground(String... params)
{
// background computation
return "hello"; // return string
}
#Override
protected void onPostExecute(String result) // string
{
super.onPostExecute(result);
fieldOne.setText(result); // hello is set to field One
}
For more info read the topic under The4Steps in the docs
http://developer.android.com/reference/android/os/AsyncTask.html
AsyncTask has 3 methods to override:
1: onPreExecute
Executes on UI thread. So do what you want to do on UI before service call here(Ex: show a progress dialog).
2: doInBackground
Executes in background so perform long running task like fetching data from server.
3: onPostExecute
Executes on UI thread and gets called once doInBackground is completed you can process the result here and update the UI
Ex:
public class RestServiceTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
}
#Override
protected void onPostExecute(String result) {
}
}

How to use AsyncTask correctly in Android [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I don't want to pass any arguments to doInBackground method of the AsyncTask.
So what should be the code like?
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
public class AsyncExample extends Activity{
private String url="http://www.google.co.in";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
new AsyncCaller().execute();
}
private class AsyncCaller extends AsyncTask<Void, Void, Void>
{
ProgressDialog pdLoading = new ProgressDialog(AsyncExample.this);
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method will be running on UI thread
pdLoading.setMessage("\tLoading...");
pdLoading.show();
}
#Override
protected Void doInBackground(Void... params) {
//this method will be running on background thread so don't update UI frome here
//do your long running http tasks here,you dont want to pass argument and u can access the parent class' variable url over here
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
//this method will be running on UI thread
pdLoading.dismiss();
}
}
}
According to AsyncTask, its
AsyncTask<Params, Progress, Result>
Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the
background computation.
Result, the type of the result of the background computation.
So if you want to pass void in doInBackground just pass void in place of Params.
Example code:
class DownloadLink extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
//Do Your stuff here..
return null;
}
}
And call it as:
new DownloadLink().execute();
Create your AsyncTask class as if you don't want to pass any parameter to doInBackground :
public class LongOperation extends AsyncTask<Void, Void, String> {
public LongOperation(Context context) {
}
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(Void... params) {
return null;
}
#Override
protected void onPostExecute(String result) {
}
}
and start AsyncTask as without passing any parameter to execute :
LongOperation longOperation = new LongOperation(this);
longOperation.execute();
Why don't you want to pass any arguments to it? You should explain...
This is how it usually works (example):
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
And to execute it you call:
new DownloadFilesTask().execute(url1, url2, url3);
Source: Android docs

Categories

Resources