10

Well, I have an activity class with two background task (Async-Task) which have been defined in two separate classes like

public class GettingBeaconsList extends AsyncTask<String, String, String> 
public class GettingAirports extends AsyncTask<String, String, String> 

which are initialized and executed in MainClass

public class MainClass extends Activity implements DelegateTaskCompleted
{

     int ServiceBoolean = 0;
     public OnClickListener LoadingBeaconList = new OnClickListener()
     {
         public void onClick(View v)
         {
             ServiceBoolean  =1;
             new GettingBeaconsList (context,MainClass.this).execute();
         }
     }

    public OnClickListener LoadingAirportList= new OnClickListener()
    {
         public void onClick(View v)
         {
             ServiceBoolean  =2;
             new GettingAirports(context,MainClass.this).execute();
         }
    }


    @Override
    public void JsonArrayLoaded(JSONArray result) 
    {
        // bla bla or whatever here i write, does not matter
         if(ServiceBoolean  == 1)   { 
                //  Load activity 5
         }

         else if( ServiceBoolean  == 2)
         { 
             //  Load activity 6

         }

        else if( ServiceBoolean==3 )
        {
            // display Toast or Alert Box or load Activity number 8
        } 


    }

}

Now in above code MainClass.this is stored as Interface Reference in AsynTask SubClasses like this

private Context context             =   null;
private DelegateTaskCompleted delegate      =   null;

public GettingBeaconsList (Context context,DelegateTaskCompleted delegate)  
{   
    this.context        =   context;
    this.delegate       =   delegate;
}

// And constructor of second AsynTask is same as of First AsynTask Class

private Context context             =   null;
private DelegateTaskCompleted delegate      =   null;

public GettingAirports (Context context,DelegateTaskCompleted delegate) 
{   
    this.context        =   context;
    this.delegate       =   delegate;
}

onPostExecute of each AsynTask class or subclass, JSONArray is returned or passed back to the calling class, shown below. In this case calling class is MainClass but there are other activity classes which use same AsynTask Classes(GettingBeaconsList and GettingAirports)

protected void onPostExecute(String file_url)   
{           
    pDialog.dismiss();      
    delegate.JsonArrayLoaded(gotNearestbeacons);
}

Now I have one method (JsonArrayLoaded) in MainClass to tackle two response coming from two different background task or services. I am using condition to figure out which service/class or AsynTask is executed.

But I am asking for the best way to tackle such scenario as if we have 5 or more background services in future and they just also return a JSON Array so do I need to make separate interfaces for each services ?

What should be object oriented way out to this case ?

Karthik Balakrishnan
  • 4,353
  • 6
  • 37
  • 69
Muhammad Irfan
  • 1,447
  • 4
  • 26
  • 56
  • 2
    name for the interface is not proper too. Please follow proper naming conventions while posting examples. – Narendra Pathai Jan 10 '13 at 08:20
  • 2
    where is result being used in the Main class? Please edit the post and give a proper example. Not making sense – Narendra Pathai Jan 10 '13 at 08:23
  • 1
    @MuhammadIrfan So, for your question regarding an _object oriented way_ to solve your issue, you chose the answer which is least object oriented? I'd say that's cool. :) – class stacker Jan 23 '13 at 12:22

6 Answers6

14

This is the interface for callback

public interface CallbackReceiver {
    public void receiveData(Object result);

}

Use Asynctask class as Abstract class

public abstract class JsonDataCallback extends AsyncTask<String, String, String> implements CallbackReceiver {
private ProgressDialog mProgressDialog;
Handler handler;
Runnable callback;
Activity activity;


public JsonDataCallback(Activity activity) 
{
     this.activity=activity;
     mProgressDialog = new ProgressDialog(activity);
     mProgressDialog.setMessage("Loading Please Wait.");
     mProgressDialog.setIndeterminate(false);
     mProgressDialog.setMax(100);
     mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
     mProgressDialog.setCancelable(true);
}

public abstract void receiveData(Object object);
@Override
protected void onPreExecute() {
    mProgressDialog =ProgressDialog.show(activity, "", "Please Wait",true,false);
    super.onPreExecute();
}

@Override
protected String doInBackground(String... aurl) {
    String results="";
    // do stuff
    return results;
}


@Override
protected void onPostExecute(String jsonData) {
     if (mProgressDialog != null || mProgressDialog.isShowing()){
         mProgressDialog.dismiss();
 }
     if(jsonData!=null)
     {
         receiveData(jsonData);
     }
}
}

And in your code use it like this

String url = ipaddress + "/GrantAdvanceList;
            JsonDataCallback callbackservice = new JsonDataCallback(yourActivity.this) {
                @Override
                public void receiveData(Object object) {
                    jsonRecordsData = (String)object;
                    //do stuff with call back data
                }
            };

        callbackservice.execute(url, null, null);

You can reuse the code this way.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Pragnani
  • 20,075
  • 6
  • 49
  • 74
7

The most simplistic solution I can think of is to modify your DelegateTaskCompleted interface so as it looks like this:

public interface DelegateTaskCompleted{
  public void JsonArrayLoaded(AsyncTask<String, String, String> task, 
                              JSONArray result);
}

Then your onPostExecute will send itself back like below:

protected void onPostExecute(String file_url)   
{           
    pDialog.dismiss();      
    delegate.JsonArrayLoaded(this, gotNearestbeacons);
}

Finally, in your MainClass, you can have a conditional check based on the type of AsyncTask:

 @Override
 public void JsonArrayLoaded(AsyncTask<String, String, String> task,
                             JSONArray result) 
    {
         if(task instanceof GettingBeaconsList) { 
                //  do stuff related to the beacon list
         }

         else if(task instanceof GettingAirports) { 
            // do airport list stuff
         }

    }

That way you can easily identify the AsyncTask that sends through the response without having to track which it is, if one takes longer than the other etc.


Alternatively, have another class that extends AsyncTask but adds an abstract variable for identification.

public class TrackableAsyncTask extends AsyncTask<String, String, String>{
    public abstract int getId();

    public static final int ID_AIRPORT = 1;
    public static final int ID_BEACONS = 2;
    ... etc
}

Then have your Airport and Beacon AsycTasks extend this instead. This will require them to implement the getId method.

public class GettingAirports extends AsyncTask<String, String, String> {
     public int getId(){
        return ID_AIRPORT;
     }
}

And then instead of doing a conditional if (task instanceof GettingAirports) you can do a switch statement like below:

switch(task.getId()){
   case TrackableAsyncTask.ID_AIRPORT:
       // run airport code
}

Hope this helps.

biddulph.r
  • 5,226
  • 3
  • 32
  • 47
  • Could you describe what you think is object oriented about your approach? Citing the OP: _What should be object oriented way out to this case?_ – class stacker Jan 23 '13 at 09:29
6

If I understand your problem correctly, you've extended AsyncTask some number of times. The goal of each of these sub-classes is to pass a JSONArray to an Activity that implements DelegateTaskCompleted, where you will do something to it. The challenge is that the "something" that you want to do to this JSONArray is different depending upon which AsyncTask generated it.

Going off these assumptions, there are many different ways you can differentiate which AsyncTask the JSONArray came from:

  1. Create a static variable, such as an int, in your DelegateTaskCompleted class file for each type of JSONArray it needs to handle. Add a parameter to JsonArrayLoaded of the same type of this variable. Then, use your if-else statements or a switch statement that check this variable against the set and perform the actions to your JSONArray based off of it.
  2. If you have access to whatever is generating the JSONArray, make the 0 index of the Array contain information as to how to parse it. (Perhaps something you can compare with if-else or a switch)
  3. As you suggested, creating a separate interface for each AsyncTask, or alternatively one single Interface with multiple methods.

Only option 3 is an Object Oriented solution, and as has been pointed out in the comments, not a great one due to scalability. This is by no means a complete list, just some of my ideas.

I'm wondering though, if it's worth it to use Interfaces at all, or at least in the way presented. Since you already have different sub-classes of AsyncTask to handle generating the JSONArrays, why not do whatever it is you're doing to them within the doInBackground() method off the main thread, or at least place that logic somewhere in those classes, and just return the results (or possibly stuff them in a database and get them when needed). I'm thinking that there may be a better way to handle your AsyncTask inheritance that avoids Interfaces all together, or at least uses them differently, such as a single Interface being implemented by all your AsyncTasks.

It would be really helpful if you can clarify your question and explain the type of operations both the AsyncTasks and your JSONArrayLoaded method are performing, and perhaps your reasoning for using Interfaces the way you are. It's hard to give a concrete OO answer or advice on OO best practices with so little information as to what your code actually is doing and hopes to achieve.

MattDavis
  • 5,158
  • 2
  • 23
  • 35
  • I am fetching records from database in json format in doInBackground(). Different AysnTask fetches different records as JSONArray. – Muhammad Irfan Jan 17 '13 at 06:42
  • Interfaces are used because there are other activity classes which uses same AsynTask so To make AsynTask generic. onPostExecute method, i use delegate.JsonArrayLoaded(gotNearestbeacons); delegate is an interface representing all the activity classes here. – Muhammad Irfan Jan 17 '13 at 06:48
  • JSONArrayLoaded performs different action. I have modified a question at this section – Muhammad Irfan Jan 17 '13 at 06:53
  • As I see it, only your third suggestion addresses the OP's request for an _object oriented_ solution () -- still, it doesn't _scale_ in an object oriented fashion. – class stacker Jan 23 '13 at 09:34
  • @Class Stacker - you're absolutely right, at the time it was tough to pick out what the OP was actually trying to do, so I was really hoping to just throw some preliminary ideas out and get some more information about the problem. I'll update my answer to reflect your point, thank you! – MattDavis Jan 23 '13 at 14:43
  • @MattDavis Then again, it doesn't look like the OP was too interested in a truly object oriented solution, given his choice of the most popular, however least OO answer. ;) – class stacker Jan 23 '13 at 14:45
6

You can also consider Handler to achieve this. Create handler in Activity, Pass this handler object to each AsyncTask. In onPost call handler.sendEmptyMessage(CONSTANT_INT); In Handler handleMessage check msg.what in if or switch This way only one object of handler will be created and used within multiple calls for async from one activity

Pankaj
  • 1,242
  • 1
  • 9
  • 21
  • Could you describe what you think is object oriented about your approach? Citing the OP: _What should be object oriented way out to this case?_ – class stacker Jan 23 '13 at 09:30
4

Add one member variable to both AsyncTask classes i.e,

public class GettingBeaconsList extends AsyncTask<String, String, String> 
public class GettingAirports extends AsyncTask<String, String, String> 

as

private int flag;

and write setter for that as

public void setFlag(int flag) 
{
  this.flag = flag;
}

In MainClass :

GettingBeaconsList beaconsList = new GettingBeaconsList(context,MainClass.this);
beaconsList.setFlag(100); //Declare this flag in integer constant.
beaconsList.execute();

GettingAirports airports = new GettingAirports(context, MainClass.this);
airports.setFlag(200);
airports.execute();

In Both the AsyncTask classes pass flag with the delegate's method:-

protected void onPostExecute(String file_url)   
{           
  pDialog.dismiss();      
  delegate.JsonArrayLoaded(gotNearestbeacons, flag);
  //Change the signature of this method
}

Again in MainClass to handle response :-

@Override
public void JsonArrayLoaded(JSONArray result, int flag) 
{

    // Here check which Background task has been completed
    if(flag == 100) // GettingBeaconsList is executed

    if(flag == 200) // GettingAirport is executed.


    // bla bla or whatever here i write, does not matter
     if(ServiceBoolean  == 1)   { 
            //  Load activity 5
     }

     else if( ServiceBoolean  == 2)
     { 
         //  Load activity 6

     }

    else if( ServiceBoolean==3 )
    {
        // display Toast or Alert Box or load Activity number 8
    } 


}
Suresh
  • 7,785
  • 1
  • 16
  • 28
  • If i understood your problem in correct way then this will help you out. Good luck. – Suresh Jan 22 '13 at 14:45
  • Could you describe what you think is object oriented about your approach? Citing the OP: _What should be object oriented way out to this case?_ – class stacker Jan 23 '13 at 09:32
0

I suggest you simply use n inner classes for your Activity which implement DelegateTaskCompleted. It's simple, efficient, clear and easily understandable (think maintenance) -- and you're passing the delegate already when you construct your AsyncTasks, so could it be you already had this approach on your mind?

public class MainClass extends Activity {
    // probabnly not static ;)
    private final class BeaconsDelegate implements DelegateTaskCompleted ...
    private final class AirportsDelegate implements DelegateTaskCompleted ...
}
class stacker
  • 5,357
  • 2
  • 32
  • 65