Android: AsyncTask using Command pattern ... How Can I publish the progress? - android

I would like a more generic and easier approach for starting methods in the background. So the Command pattern looks like a good candidate.
#Full stack ex describes an implementation of the Command pattern in his post with AsyncTask .
The problem is : how can I publish the progress in my method, executing in the background, via the normal AsyncTask Progressdialog or callback?
Normally we use publishProgress( progress) ... but that is not possible. publishProgress is of scope 'protected'. Calling directly onProgressUpdate( ) updating the dialog is of course not possible, crossing the line of background process and UI process.
How can I use this or similar approach AND publish progress (via
private static interface Command {
public void execute();
}
public static final class MyWsCommand1 implements Command {
#Override
public void execute() {
// ------- TODO YOUR CODE ---------
publishProgress( 90); // similar to this
}
}
private static class GenericAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
private Command command;
public GenericAsyncTask(Command command) {
super();
this.command = command;
}
#Override
protected Result doInBackground(Params... params) {
command.execute();
return null;
}
}
private GenericAsyncTask<Object, Object, Object> myAsyncTask1;
myAsyncTask1 = new GenericAsyncTask<Object, Object, Object>(new MyWsCommand1());
myAsyncTask1.execute();

publishProgress is of scope 'protected'
That means you can call it from a child class. A protected field or method can be accessed in the class itself, and any class that inherits from it. Your original plan should work.

Related

Cannot access variables from Async Task

I am new to android.I have spent too much time solving this issue with no success.
So i have service Serv.java.
public class Serv extends Service {
private String a = "aa";
private String b = "bb";
private String c = "100";
//called by some class.
public void setcc(String s) {
c=s;//c="cc"
}
//Using alarm manager to start the service.
//I call function callMe from OnStart.
void callMe(Context context){
//which calls an async task
new VAsyncTask().execute("");
}
private class VerifyCPIAsyncTask extends AsyncTask<String, Void, Void> {
protected void onPreExecute() {
}
protected Void doInBackground(String... urls) {
//I am able to access a and b.(aa and bb)
//but not c.(It still shows 100 and not cc)
}
........
}
But when i run the same service again it shows correct value for c(cc).There is problem when i am accessing for the first time.
EDIT- The flow works fine if i make private String c to private static String c.
And i have put logs in my onCreate and onStartCommand.They do not print the latest value of variable c.so there is no use passing (latest)variable c to preexecute or even create a constructor in the aysnctask(cause i still get the old value of variable c).
Please help.
Thanks.
its difficult to tell without knowing from where/what and how your flow is?
you can override the constructor and pass the values as async task parameter .
*
private class VerifyCPIAsyncTask extends AsyncTask<String, Void, Void>
{
int cc
VerifyCPIAsyncTask (int a) {
cc= a;
}
protected void onPreExecute() {
}
}*
and call your async task as new VAsyncTask(cc).execute("");
it is safer approach.

Generic asyncTask with callback (for web services)

I've already developed many Android apps that make web service requests, always with the following approach:
In every activity that need to make a web service request, I define an inner AsyncTask that shows a ProgressDialog in onPreExecute(), makes the web service call in doInBackground, and dismisses the progressDialog and updates the results in the UI from onPostExecute().
My concern is: Is there a better (shorter) way to do it? Does it make sense to repeat all that code in every activity? I've been googling a lot, but I've found nothing.
My question is: Couldn't I define a Callback interface? for example this one:
public interface RequestCallback {
public void onSuccess(Whatever whatever);
public void onError(ErrorCode errorCode, String message);
}
... and then define an external class, for example AsyncRequest, that wraps the AsyncTask definition and the ProgressDialog show() and dismiss() statements. So, all activities would just need to instantiate that class, and pass in the following parameters:
1) The method of the web service to run
2) A Bundle with all the parameters of that method of the web service
3) A RequestCallback instance (that could be an anonymous inline instance, where I could update the UI from onSuccess())
4) The context of the Activity (necessary to show the ProgressDialog(), so I would still need a way to prevent configuration change exceptions and so...),
Do you find this a good design? It could save hundreds of lines of code...
Your approach is what I did on my project. And it saved a lot of code as you said, I don't have any complaint about it. But here is some issues that I want to tell you:
You should create new instance of AsyncTask every time you do a background thread to avoid to pile callback.
For the progress dialog, I use it as Singleton, because you don't show many dialogs at the same time. The dialog will be showed when you call the background job, and will be dismiss in the callback. Here is what I did:
private void showProgressDialog(String strMess){
if(null == progressDialog){
progressDialog = new ProgressDialog(MainActivity.this);
}
if(!progressDialog.isShowing()){
progressDialog.setMessage(strMess);
progressDialog.show();
}
}
private void hideProgressDialog(){
if(null != progressDialog && progressDialog.isShowing()){
progressDialog.dismiss();
}
}
void someMethod(){
showProgressDialog("Loading...");
doBackgroundJob(param, new RequestCallBack() {
public void onRequestCompleted(String message, boolean isSuccess) {
hideProgressDialog();
if(isSuccess){
}else{
//do something on error
}
}
});
}
It is an optional, I defined an interface to notify instead of specific class, for each response I use one class, so in base class, I don't care what the response is. Here is it:
public interface OnRequestCompleted<TResponse> {
void requestCompleted(TResponse response);
}
public abstract class BaseRequest<TResponse> implements IRequest{
protected OnRequestCompleted<TResponse> delegate;
protected Class<TResponse> responseClass;
#Override
public void send() {
new HttpTask().execute();
}
private class HttpTask extends AsyncTask<Void, Void, String> {
//...
#Override
protected void onPostExecute(String result) {
if (null != response && null != delegate) {
delegate.requestCompleted(response);
}
}
}
// the response example
public class GroupResponse {
public static class Clip {
public int clipId;
public String detail;
}
public static class Movie {
public int movieId;
public String detail;
}
}
In the subclass of BaseRequest, I will tell it exactly what the response class is (Movie, Clip...)
Hope this help.
If you use it already and it works for you, then yes it makes sense to make it generic and save the time (and bugs) of reimplementing the same thing dozens of times. If you ever find yourself copy-pasting large sections of code with few to no differences you should turn it into a library function or class of some sort. Otherwise if you find a problem later you'll have to fix it in a dozen places. It doesn't even matter if you think of a better way to do things later- its still easier to change it in one place than a dozen.
The only real issue I'd have with your solution is I wouldn't add the progress bar to it- I'd handle it in the calling code and the onSuccess/onError implementations. That way you could also reuse it for a background call that doesn't need to put up a UI. I try to keep my UI decisions as far away from data grabbing code as possible, MVC patterns are good.

Generic asynctask for ws calls in Android

I'm using AsyncTask class to execute WS methods. I would like to have a generic async task class to call any method in the WS.
I create a set of classes that works fine but the problem is when I have to update the UI. I know I can create the async task with a reference to the Activity class and then execute the desired method, but what I want is the method to execute to be also a parameter.
Otherwise I have to implement a new class for each method which interacts with the UI because each action is different depending on the method.
Provably the solution is to use Listeners combined with parameters but I didn't find a complete example of how to use this.
In Java, you cannot pass a method as a parameter, but you can pass an object that extends or implements an ancestor and overrides that method. The Command pattern uses this concept (http://en.wikipedia.org/wiki/Command_pattern).
Here's an idea of the approach:
private static interface Command {
public void execute();
}
public static final class MyWsCommand1 implements Command {
#Override
public void execute() {
// TODO your WS code 1
}
}
public static final class MyWsCommand2 implements Command {
#Override
public void execute() {
// TODO your WS code 2
}
}
private static class GenericAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
private Command command;
public GenericAsyncTask(Command command) {
super();
this.command = command;
}
#Override
protected Result doInBackground(Params... params) {
// TODO your code
command.execute();
// TODO your code
return null;
}
}
private GenericAsyncTask<Object, Object, Object> myAsyncTask1;
private GenericAsyncTask<Object, Object, Object> myAsyncTask2;
And use those in your code:
myAsyncTask1 = new GenericAsyncTask<Object, Object, Object>(new MyWsCommand1());
myAsyncTask1.execute();
...
myAsyncTask2 = new GenericAsyncTask<Object, Object, Object>(new MyWsCommand2());
myAsyncTask2.execute();
by WS , you mean webservice?
asyncTask is not meant to be used for such long tasks . they are supposed to do small tasks . things that take (approx.) less than 5 seconds .
if you wish to do very long tasks , use a simple thread and consider putting it in a service.
also , in order to communicate with it , you can communicate with the service , and when you need to post something to the UI thread , use a handler .
The most close answer is this
You can choose the method in the same UI which waits until the background process ends
I would use Async, and I did on a production implementation. The issue you'll run into is doing more logic in the doInBackground because if you watch your debug build any time you see it say "Skipped X Frames" you may want to do a lot of post processing in doInBackground still.
Using an interface is the best approach, it's how I implemented my Async class. full.stack.ex hit the nail on the head with that answer. That answer shows a clear, simple, powerful way to extend Async and use it for your purpose.

How to pass variables in and out of AsyncTasks?

I haven't spent much time working with AsyncTasks in Android. I'm trying to understand how to pass variables to and from the class. The syntax:
class MyTask extends AsyncTask<String, Void, Bitmap>{
// Your Async code will be here
}
it's a little bit confusing with the < > syntax on the end of the class definition. Never seen that type of syntax before. It seems like I'm limited to only passing one value into the AsyncTask. Am I incorrect in assuming this? If I have more to pass, how do I do that?
Also, how do I return values from the AsyncTask?
It's a class and when you want to use it you call new MyTask().execute() but the actual method you use in the class is doInBackground(). So where do you actually return something?
Note: all of the information below is available on the Android Developers AsyncTask reference page. The Usage header has an example. Also take a look at the Painless Threading Android Developers Blog Entry.
Take a look at the source code for AsynTask.
The funny < > notation lets you customize your Async task. The brackets are used to help implement generics in Java.
There are 3 important parts of a task you can customize:
The type of the parameters passed in - any number you want
The type for what you use to update the progress bar / indicator
The type for what you return once done with the background task
And remember, that any of the above may be interfaces. This is how you can pass in multiple types on the same call!
You place the types of these 3 things in the angle brackets:
<Params, Progress, Result>
So if you are going to pass in URLs and use Integers to update progress and return a Boolean indicating success you would write:
public MyClass extends AsyncTask<URL, Integer, Boolean> {
In this case, if you are downloading Bitmaps for example, you would be handling what you do with the Bitmaps in the background. You could also just return a HashMap of Bitmaps if you wanted. Also remember the member variables you use are not restricted, so don't feel too tied down by params, progress, and result.
To launch an AsyncTask instantiate it, and then execute it either sequentially or in parallel. In the execution is where you pass in your variables. You can pass in more than one.
Note that you do not call doInBackground() directly. This is because doing so would break the magic of the AsyncTask, which is that doInBackground() is done in a background thread. Calling it directly as is, would make it run in the UI thread. So, instead you should use a form of execute(). The job of execute() is to kick off the doInBackground() in a background thread and not the UI thread.
Working with our example from above.
...
myBgTask = new MyClass();
myBgTask.execute(url1, url2, url3, url4);
...
onPostExecute will fire when all the tasks from execute are done.
myBgTask1 = new MyClass().execute(url1, url2);
myBgTask2 = new MyClass().execute(urlThis, urlThat);
Notice how you can pass multiple parameters to execute() which passes the multiple parameter on to doInBackground(). This is through the use of varargs (you know like String.format(...). Many examples only show the extraction of the first params by using params[0], but you should make sure you get all the params. If you are passing in URLs this would be (taken from the AsynTask example, there are multiple ways to do this):
// This method is not called directly.
// It is fired through the use of execute()
// It returns the third type in the brackets <...>
// and it is passed the first type in the brackets <...>
// and it can use the second type in the brackets <...> to track progress
protected Long doInBackground(URL... urls)
{
int count = urls.length;
long totalSize = 0;
// This will download stuff from each URL passed in
for (int i = 0; i < count; i++)
{
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
// This will return once when all the URLs for this AsyncTask instance
// have been downloaded
return totalSize;
}
If you are going to be doing multiple bg tasks, then you want to consider that the above myBgTask1 and myBgTask2 calls will be made in sequence. This is great if one call depends on the other, but if the calls are independent - for example you are downloading multiple images, and you don't care which ones arrive first - then you can make the myBgTask1 and myBgTask2 calls in parallel with the THREAD_POOL_EXECUTOR:
myBgTask1 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url1, url2);
myBgTask2 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urlThis, urlThat);
Note:
Example
Here is an example AsyncTask that can take as many types as you want on the same execute() command. The restriction is that each type must implement the same interface:
public class BackgroundTask extends AsyncTask<BackgroundTodo, Void, Void>
{
public static interface BackgroundTodo
{
public void run();
}
#Override
protected Void doInBackground(BackgroundTodo... todos)
{
for (BackgroundTodo backgroundTodo : todos)
{
backgroundTodo.run();
// This logging is just for fun, to see that they really are different types
Log.d("BG_TASKS", "Bg task done on type: " + backgroundTodo.getClass().toString());
}
return null;
}
}
Now you can do:
new BackgroundTask().execute(this1, that1, other1);
Where each of those objects is a different type! (which implements the same interface)
I recognize that this is a late answer, but here's what I've been doing for the last while.
When I'm needing to pass in a bunch of data to an AsyncTask, I can either create my own class, pass that in and then access it's properties, like this:
public class MyAsyncTask extends AsyncTask<MyClass, Void, Boolean> {
#Override
protected Boolean doInBackground(MyClass... params) {
// Do blah blah with param1 and param2
MyClass myClass = params[0];
String param1 = myClass.getParam1();
String param2 = myClass.getParam2();
return null;
}
}
and then access it like this:
AsyncTask asyncTask = new MyAsyncTask().execute(new MyClass());
or I can add a constructor to my AsyncTask class, like this:
public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
private String param1;
private String param2;
public MyAsyncTask(String param1, String param2) {
this.param1 = param1;
this.param2 = param2;
}
#Override
protected Boolean doInBackground(Void... params) {
// Do blah blah with param1 and param2
return null;
}
}
and then access it like this:
AsyncTask asyncTask = new MyAsyncTask("String1", "String2").execute();
Hope this helps!
Since you can pass array of objects in the square bracket, that is the best way to pass data based on which you want to do processing in the background.
You could pass the reference of your activity or the view in the Constructor and use that to pass data back into your activity
class DownloadFilesTask extends AsyncTask<URL, Integer, List> {
private static final String TAG = null;
private MainActivity mActivity;
public DownloadFilesTask(MainActivity activity) {
mActivity = activity;
mActivity.setProgressBarIndeterminateVisibility(true);
}
protected List doInBackground(URL... url) {
List output = Downloader.downloadFile(url[0]);
return output;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
private void setProgressPercent(final Integer integer) {
mActivity.setProgress(100*integer);
}
protected void onPostExecute(List output) {
mActivity.mDetailsFragment.setDataList((ArrayList<Item>) output);
//you could do other processing here
}
}
Alternatively, you could just use a regular thread and usea handler to send data back to the ui thread by overriding the handlemessage function.
Passing a simple String:
public static void someMethod{
String [] variableString= {"hello"};
new MyTask().execute(variableString);
}
static class MyTask extends AsyncTask<String, Integer, String> {
// This is run in a background thread
#Override
protected String doInBackground(String... params) {
// get the string from params, which is an array
final String variableString = params[0];
Log.e("BACKGROUND", "authtoken: " + variableString);
return null;
}
}

Android: How can I pass parameters to AsyncTask's onPreExecute()?

I use an AsyncTask for loading operations that I implemented as an inner class.
In onPreExecute() I show a loading dialog which I then hide again in onPostExecute(). But for some of the loading operations I know in advance that they will finish very quickly so I don't want to display the loading dialog.
I wanted to indicate this by a boolean parameter that I could pass to onPreExecute() but apparently for some reason onPreExecute() doesn't take any parameters.
The obvious workaround would probably be to create a member field in my AsyncTask or in the outer class which I would have to set before every loading operation but that does not seem very elegant. Is there a better way to do this?
You can override the constructor. Something like:
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
public MyAsyncTask(boolean showLoading) {
super();
// do stuff
}
// doInBackground() et al.
}
Then, when calling the task, do something like:
new MyAsyncTask(true).execute(maybe_other_params);
Edit: this is more useful than creating member variables because it simplifies the task invocation. Compare the code above with:
MyAsyncTask task = new MyAsyncTask();
task.showLoading = false;
task.execute();
1) For me that's the most simple way passing parameters to async task
is like this
// To call the async task do it like this
Boolean[] myTaskParams = { true, true, true };
myAsyncTask = new myAsyncTask ().execute(myTaskParams);
Declare and use the async task like here
private class myAsyncTask extends AsyncTask<Boolean, Void, Void> {
#Override
protected Void doInBackground(Boolean...pParams)
{
Boolean param1, param2, param3;
//
param1=pParams[0];
param2=pParams[1];
param3=pParams[2];
....
}
2) Passing methods to async-task
In order to avoid coding the async-Task infrastructure (thread, messagenhandler, ...) multiple times you might consider to pass the methods which should be executed in your async-task as a parameter. Following example outlines this approach.
In addition you might have the need to subclass the async-task to pass initialization parameters in the constructor.
/* Generic Async Task */
interface MyGenericMethod {
int execute(String param);
}
protected class testtask extends AsyncTask<MyGenericMethod, Void, Void>
{
public String mParam; // member variable to parameterize the function
#Override
protected Void doInBackground(MyGenericMethod... params) {
// do something here
params[0].execute("Myparameter");
return null;
}
}
// to start the asynctask do something like that
public void startAsyncTask()
{
//
AsyncTask<MyGenericMethod, Void, Void> mytest = new testtask().execute(new MyGenericMethod() {
public int execute(String param) {
//body
return 1;
}
});
}
why, how and which parameters are passed to Asynctask<>, see detail here. I think it is the best explanation.
Google's Android Documentation Says that :
An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
AsyncTask's generic types :
The three types used by an asynchronous task are the following:
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.
Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }
You Can further refer : http://developer.android.com/reference/android/os/AsyncTask.html
Or You Can clear whats the role of AsyncTask by refering Sankar-Ganesh's Blog
Well The structure of a typical AsyncTask class goes like :
private class MyTask extends AsyncTask<X, Y, Z>
protected void onPreExecute(){
}
This method is executed before starting the new Thread. There is no input/output values, so just initialize variables or whatever you think you need to do.
protected Z doInBackground(X...x){
}
The most important method in the AsyncTask class. You have to place here all the stuff you want to do in the background, in a different thread from the main one. Here we have as an input value an array of objects from the type “X” (Do you see in the header? We have “...extends AsyncTask” These are the TYPES of the input parameters) and returns an object from the type “Z”.
protected void onProgressUpdate(Y y){
}
This method is called using the method publishProgress(y) and it is usually used when you want to show any progress or information in the main screen, like a progress bar showing the progress of the operation you are doing in the background.
protected void onPostExecute(Z z){
}
This method is called after the operation in the background is done. As an input parameter you will receive the output parameter of the doInBackground method.
What about the X, Y and Z types?
As you can deduce from the above structure:
X – The type of the input variables value you want to set to the background process. This can be an array of objects.
Y – The type of the objects you are going to enter in the onProgressUpdate method.
Z – The type of the result from the operations you have done in the background process.
How do we call this task from an outside class? Just with the following two lines:
MyTask myTask = new MyTask();
myTask.execute(x);
Where x is the input parameter of the type X.
Once we have our task running, we can find out its status from “outside”. Using the “getStatus()” method.
myTask.getStatus();
and we can receive the following status:
RUNNING - Indicates that the task is running.
PENDING - Indicates that the task has not been executed yet.
FINISHED - Indicates that onPostExecute(Z) has finished.
Hints about using AsyncTask
Do not call the methods onPreExecute, doInBackground and onPostExecute manually. This is automatically done by the system.
You cannot call an AsyncTask inside another AsyncTask or Thread. The call of the method execute must be done in the UI Thread.
The method onPostExecute is executed in the UI Thread (here you can call another AsyncTask!).
The input parameters of the task can be an Object array, this way you can put whatever objects and types you want.
You can either pass the parameter in the task constructor or when you call execute:
AsyncTask<Object, Void, MyTaskResult>
The first parameter (Object) is passed in doInBackground.
The third parameter (MyTaskResult) is returned by doInBackground. You can change them to the types you want. The three dots mean that zero or more objects (or an array of them) may be passed as the argument(s).
public class MyActivity extends AppCompatActivity {
TextView textView1;
TextView textView2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
textView1 = (TextView) findViewById(R.id.textView1);
textView2 = (TextView) findViewById(R.id.textView2);
String input1 = "test";
boolean input2 = true;
int input3 = 100;
long input4 = 100000000;
new MyTask(input3, input4).execute(input1, input2);
}
private class MyTaskResult {
String text1;
String text2;
}
private class MyTask extends AsyncTask<Object, Void, MyTaskResult> {
private String val1;
private boolean val2;
private int val3;
private long val4;
public MyTask(int in3, long in4) {
this.val3 = in3;
this.val4 = in4;
// Do something ...
}
protected void onPreExecute() {
// Do something ...
}
#Override
protected MyTaskResult doInBackground(Object... params) {
MyTaskResult res = new MyTaskResult();
val1 = (String) params[0];
val2 = (boolean) params[1];
//Do some lengthy operation
res.text1 = RunProc1(val1);
res.text2 = RunProc2(val2);
return res;
}
#Override
protected void onPostExecute(MyTaskResult res) {
textView1.setText(res.text1);
textView2.setText(res.text2);
}
}
}

Categories

Resources