Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 ?

like image 267
Muhammad Irfan Avatar asked Jan 10 '13 08:01

Muhammad Irfan


People also ask

What is the current recommended way to handle long running background tasks in Android?

Recommended solutionScheduling deferred work through WorkManager is the best way to handle tasks that don't need to run immediately but which ought to remain scheduled when the app closes or the device restarts.

What is the use of interface in Android?

It is used to provide total abstraction. That means all the methods in an interface are declared with an empty body and are public and all fields are public, static, and final by default. A class that implements an interface must implement all the methods declared in the interface.


2 Answers

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.

like image 170
Pragnani Avatar answered Sep 21 '22 23:09

Pragnani


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.

like image 20
biddulph.r Avatar answered Sep 21 '22 23:09

biddulph.r