可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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:
- 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. - 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)
- 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 ... }