How one interface can be used for different background android tasks?

匿名 (未验证) 提交于 2019-12-03 07:50:05

问题:

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  public class GettingAirports extends AsyncTask

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 ?

回答1:

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 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 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{     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 {      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.



回答2:

Hi this code will help you

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 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, I hope this will help you. Thanks in advance.



回答3:

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



回答4:

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.



回答5:

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

public class GettingBeaconsList extends AsyncTask  public class GettingAirports extends AsyncTask

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     }    } 


回答6:

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 ... } 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!