Am i fully utilising my AsyncTask? Can someone correct my codes if it is wrong. I just want to make sure my AsyncTask fully works so i wont get any trouble in the future. I wish to use AsyncTask for all my classes. Is it a good practice?
public class SingleMenuItemActivity extends Activity {
// XML node keys
static final String KEY_TITLE = "title";
static final String KEY_ARTIST = "artist";
static final String KEY_THUMB_URL = "thumb_url";
private ProgressDialog pDialog;
String title;
String artist;
String image_url;
ImageView view;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.single_list_item);
new loadSingleView().execute();
view = (ImageView) findViewById(R.id.single_image);
}
public class loadSingleView extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(
SingleMenuItemActivity.this);
pDialog.setMessage("Connecting to Server ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected String doInBackground(String... args) {
// updating UI from Background Thread
Intent in = getIntent();
image_url = in.getStringExtra(KEY_THUMB_URL);
title = in.getStringExtra(KEY_TITLE);
artist = in.getStringExtra(KEY_ARTIST);
return null;
}
#Override
protected void onPostExecute(String args) {
// dismiss the dialog after getting all products
ImageLoader imgLoader = new ImageLoader(getApplicationContext());
imgLoader.DisplayImage(image_url, view);
TextView lblName = (TextView) findViewById(R.id.name_title);
TextView lblCost = (TextView) findViewById(R.id.name_artist);
lblName.setText(title);
lblCost.setText(artist);
pDialog.dismiss();
}
}
You cant update the UI from Backgroud thread. For example Use doInBackground() to get data from server.All this process will be done in Background.And onPostExecute is to update the UI after background process is over
For more info Study here
Example1
Example2
You can find many more in Google :)
You have to update the UI from the method onPostExecute(). I like to move my task into their own files. This way we have a separation of concerns which makes it more easier to understand the code. We can do this by using a interface to define a callback method
public class LoadSingleView extends AsyncTask<String, String, String> {
public interface LoadSingleViewHandler {
void onSingleViewLoad(String result);
}
private LoadSingleViewHandler handler;
public LoadSingleView(LoadSingleViewHandler handler) {
this.handler = handler;
}
#Override
protected String doInBackground(String... args) {
// Do operation here and return the result
// Operation is usually some network request
// or something that will take alot of time
}
#Override
protected void onPostExecute(String result) {
handler.onSingleViewLoad(result);
}
}
Now just start the task from the activity and have the activity implement LoadSingleViewHandler interface.
Yes, all UI operations have to be done on the main thread, period. You can download the image you want to display in doInBackground(), update the entire UI in onPostExecute().
Also, it's a good practice to move the AsyncTask out of your activity. It is a little more work, but as the app becomes bigger and more complicated, it will make your life easier. You can use handlers to pass data from AsyncTask to your activities.
Do in background must mainly be used for those tasks that must not be performed on UI threads so Use it for connecting to server(API's) to receive and send data.
Dont use it without necessity...
Related
I am trying to download a file at android using AsyncTask. Because I want to download many files I want to pass the url of the file by arguments. Also I want to change the UI when a user clicks the button that triggers the AsyncTask. As I figured out, apart from the URL I need to pass and the Activity itself so I can have access to it's views so I can change them. And my problem is this how can make the AsyncTask take multiple and different arguments.
Questions:
1.The only way to do this I think is to pass as Object the first argument so anything can pass, right?
public final Example extends AsyncTask<Objects, String, String>
2.When I call the AsyncTask how do I write the function?
Example a=new Example(??????); //I want to pass both a URL and something to give me access to the UI
a.execute(?????);
3. How can I use the "something" stated above argument to change visibility for example at a view?
Thx In advance for your time
Try this..
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
new Example("URL","something").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new String[]{null});
else
new Example("URL","something").execute(new String[]{null});
and Example AsyncTask Class
public class Example extends AsyncTask<String, Void, JSONObject> {
// variables passed in:
String url;
String something;
// constructor
public Example(String url, String something) {
this.url = url;
this.something = something;
}
#Override
protected void onPreExecute() {
}
#Override
protected JSONObject doInBackground(String... args) {
}
#Override
protected void onPostExecute(JSONObject jObjOut) {
}
}
AsyncTask takes 3 generic types:
1st is the argument which you send to execution;
2nd is for publishing updates on UI
3rd is for returning result
If you want to skip one or all of them use Void class:
example: new AsyncTask();
If you want to use your own constructor in AsyncTask you should define it in your own class that extends AsyncTask, something like this:
import android.app.Activity;
import android.os.AsyncTask;
public class Example extends AsyncTask<Object, String, String>{
private Object data;
private String data1;
private String data2;
private Activity activity;
public Example(Object data, String data1, String data2, Activity activity){
this.data = data;
this.data1 = data1;
this.data2 = data2;
this.activity = activity;
}
#Override
protected String doInBackground(Object... arg0) {
//Do here all your needs except UI updating
//transfer data you need for UI updating like this:
publishProgress("UI update data argument");
return null;
}
#Override
protected void onProgressUpdate(String... arg){
super.onProgressUpdate(arg);
//Update your UI using activity
}
}
To execute your Async task :
new Example(data, data1, data2, activity).execute(object);
You can use a parameterized constructor to achieve the same. But be aware that if you have multiple arguments you would end up creating multiple constructors. Since you need to modify multiple activities in response you need to pass a context as well.
query = UtilityClass.getQueries(UtilityClass.CHECKRIDE, paramsList);
new Example(HomeActivity.this, UtilityClass.CHECKRIDE).execute(query);
This is how you can create a query/url and pass it to the AsyncTask.
A Sample AsyncTask :
public class Example extends AsyncTask<String , Void, String> {
public Example(Context contextVar, int calloutTypeVar){
context = contextVar;
CALLOUTTYPE = calloutTypeVar;
}
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(context, "Please wait", "Loading...");
}
#Override
protected String doInBackground(String...sqlQueryList) {
String result = "";
String sqlQuery = sqlQueryList[0];
result = UtilityClass.doHttpCallout(sqlQuery);
return result;
}
// Handle the response from the callout
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
progressDialog.dismiss();
switch (CALLOUTTYPE) {
case UtilityClass.SCHEDULERIDE:
ResponseHandlerClass.scheduleRide(result, context);
break;
}
}
I have implemented a response handler to handle the response from various callout results.
Hope this helps in handling your response from different urls.
The idea behind using AsyncTask is to avoid penalizing the responsiveness of the UI when performing blocking operations such as the file download of your scenario. When you use AsyncTask, the doInBackground method executes in another thread than the UI and the UI can not be modified from it so there is no point in passing any UI related data to it.
In order to modify your UI upon your background work completion, you can use the onPostExecute method. As #Tamilan suggested, you may pass the Activity object to the constructor of your AsyncTask if you want to use it there.
An example task could be as follows. Notice that you may replace String with URL, or even Object if you still want to pass different object types to the doInBackground method. Also, this example does not cover error handling beyond returning a simple boolean.
private class ExampleTask extends AsyncTask<String, Integer, Boolean>
{
private Activity mActivity;
public ExampleTask(Activity activity)
{
mActivity = activity;
}
#Override
protected Boolean doInBackground(String... params) {
// this is executed in a background thread
boolean success = true;
// do your background operations
publishProgress(50);
// more operations
return Boolean.valueOf(success);
}
#Override
protected void onProgressUpdate(Integer... progress) {
updateProgressbar(progress[0]); // update UI
}
#Override
protected void onPostExecute(Boolean result) {
// this is executed on your UI thread
if (!result)
// show error
else
// modify your UI
}
}
In order to execute this task:
ExampleTask task = new ExampleTask(anActivity);
task.execute(new String[] { "oneUrl", "anotherUrl" });
I am trying to send a string from one class to another using AsyncTask. In the code below everything is working with no errors, but I am wanting to get the returned str from newThread.execute() and save it to the string test. I have tried test = newThread.execute(), but I that produces the following error: Type mismatch: cannot convert from AsyncTask to String.
Class1.java
public void changText(View view) {
String test = "";
NewThread newThread = new NewThread();
newThread.execute();
}
Class2.java
public class NewThread extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
String str = "this is a test";
return str;
}
Any help would be greatly appreciated.
AsyncTask doesn't work like that, AsyncTask must be subclassed to be used.
the propose of an AsyncTask is execute some code in a separate thread (different from UI thread), but the result from that code, when ready, will be delivered in onPostExecute.
So, your code will look like this:
public Class1{
String test = "";
public void changText(View view) {
NewThread newThread = new NewThread();
newThread.execute("input");
}
public class NewThread extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String str = params[0] + " this is a test";
return str;
}
#Override
protected void onPostExecute(String result) {
test = result;
}
}
}
You need a way to publish the result via some callback mechanism if you put an AsyncTask into it's own file. According to the dependency inversion principle it's better to let the AsyncTask define the callback mechanism instead of making it depend on some activity directly.
The resulting task could then look like this:
public class NewThread extends AsyncTask<String, Integer, String> {
/** A callback interface to be implemented by clients of this class */
public interface NewThreadClient {
void onNewThreadResult(String result);
}
private final NewThreadClient mClient;
public NewThread(NewThreadClient client) {
mClient = client;
}
#Override
protected String doInBackground(String... params) {
String str = "this is a test";
return str;
}
#Override
protected void onPostExecute(String result) {
mClient.onNewThreadResult(result);
}
}
To use it you'll need something that implements the callback. For example an Activity
public class TestActivity extends Activity implements NewThread.NewThreadClient {
private TextView mText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// simple textview actually intended for listviews..
setContentView(android.R.layout.simple_list_item_1);
mText = (TextView) findViewById(android.R.id.text1);
new NewThread(this).execute();
}
#Override
public void onNewThreadResult(String result) {
mText.setText(result);
}
}
The point of AsyncTask is that it does things asynchronously (while your program does other things, the result will be calculated at some point in the future). You can not (there are ways but it makes absolutely no sense) get the result immediately. test = newThread.execute() would require that the result is immediately available. If you start to wait for the result you would block any progress that could happen in the meantime.
Callbacks are the most common way to get a result at a later point in time. AsyncTask has onPostExecute built-in for that purpose (also to deliver the result within the UI thread) and you can use it directly if you make your AsyncTasks an inner class. Add another layer of callbacks and you can easily use them across classes.
See if you intend to do what i have done in following code
package com.example.myfirstapp;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
public class MyActivity extends Activity {
private String test;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
NewThread newThread = new NewThread();
newThread.execute();
}
class NewThread extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
String str = "this is a test";
return str;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
test=result;
// update the UI like view.setText(test);
}
}
}
Try this:
String test = newThread.execute().get();
The value returned from newThread.execute() is not the results of the computation; it's the AsyncTask itself. To publish your results, write a method in NewThread :
void onPostExecute(ArrayList<HashMap<String,String>> result) {
returnString = result; // or something similar
// then update the UI to reflect the results
}
As in Doc AsyncTask. execute (Params... params)
Return instance of AsyncTask.
but you are trying to assign AsyncTask instance to String. to get result back from Asynctask as String you should call execute().get() method on main thread as:
NewThread newThread = new NewThread();
String test= newThread.execute().get(); //<< get String from doInBackground
but this will stop execution of main thread until doInBackground method execution not completed.
if you want to get result from doInBackground without stopping execution of main thread then use onPostExecute for updating UI because this method called on Main UI Thread when doInBackground execution complete :
#Override
protected void onPostExecute(String result) {
test = result; //<< get result here
}
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) {
}
}
I'm using "include" on my main layout. Each one of them is a RelativeLayout which needs an OnClick listener to be attached, and update some information related.
So I've tried to do it simply by:
setContentView(R.layout.allobjects);
ObjectListeners objectListeners = new ObjectListeners(objects);
for(int i=0;i<1;i++)
{
RelativeLayout objectBoxRelativeLayout = (RelativeLayout)findViewById(R.id.object1 + i);
objectBoxRelativeLayout.setOnClickListener(objectListeners.GetObjectListener(i));
SomeObject currentObject = this.objects.get(i);
Object viewObject = findViewById(R.id.object1 + i);
this.setObjectView(viewObject, currentObject);
}
The issue is that it takes too long after the "setContentView(R.layout.allobjects);" command, and the application shows black screen until it finish loading.
In addition, I use "setContentView(R.layout.allobjects);" after I perform the above commands. All of these commands have to be written after "setContentView(R.layout.allobjects);".
How can I handle that kind of situation ? Do I have to use onPreExecute and implement AsyncTask ?
Yes, AsyncTask is good solution to show loading dialog while these commands being executed.
UPDATE:
Add this class under your onCreate() function:
private class MyTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog dialog;
private Context context;
public MyTask(Activity activity) {
context = activity;
dialog = new ProgressDialog(context);
}
protected void onPreExecute() {
dialog.setTitle("Loading...");
dialog.setMessage("Loading...");
dialog.show();
}
#Override
protected Void doInBackground(Void... params) {
//do your code here in background
protected void onPostExecute(Void res) {
dialog.dismiss();
}
}
then use the task inside onCreate() like this:
MyTask mt = new MyTask(this);
mt.execute();
I have a PreferenceActivity that gets its data from a web service(Call forward Numbers, Voicemail status etc)
The class looks like this :
public class SettingsActivity extends PreferenceActivity
{
UserController userControl;
ListPreference lp;
public SharedPreferences prefs;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
userControl = new UserController(getParent());
addPreferencesFromResource(R.layout.settings);
new PullNumbersTask().execute();
}
private class PullNumbersTask extends AsyncTask<Void, Void, String[]>
{
private ProgressDialog Dialog;
private String[] numbers;
private boolean vmStatus;
private String[] cfInfo;
public PullNumbersTask()
{
Dialog = new ProgressDialog(getParent());
Dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
}
protected void onPreExecute()
{
Dialog.setMessage("Henter brugerindstillinger..");
Dialog.show();
}
#Override
protected String[] doInBackground(Void... arg0)
{
numbers = userControl.GetNumbers(); // Returns a String array containing available numbers
Dialog.setProgress(30);
vmStatus = userControl.GetVoicemailStatus(); // Returns a boolean containing voicemail status(enabled/disabled)
Dialog.setProgress(80);
cfInfo = userControl.GetCallForwardInfo(); // Returns a String array containing Call forward info.
Dialog.setProgress(100);
return null;
}
protected void onPostExecute(String[] result)
{
lp = (ListPreference) findPreference("shownumber_list");
lp.setEntries(result);
lp.setEntryValues(result);
Dialog.dismiss();
}
}
I decided that I want a single AsyncTask call to perform all my web service calls - But how do I Set the data of my preferences onPostExecute?
Instead of using a String[] as return value from the doInBackground() method, define a class inside your AyncTask with the fields you need to be passed to the onPostExecute() method.
Moreover you should avoid updating the progress dialog directly from the doInBackground() as it will not be performed in the UI thread. The AsynClass provides the possibility to pass a parameter to a onProgressUpdate() method to reflect changes in the progress of background execution.
More details here: http://developer.android.com/reference/android/os/AsyncTask.html
What doInBackground returns will passed as argument to onPostExecute.
So get your preferences from Web Services in doInBackground and just return it as string Array.
onPostExecute will have that String Array as argument. Apply preferences then.