Как один интерфейс может использоваться для различных фоновых задач андроида?

Ну, у меня есть класс активности с двумя фоновыми задачами (Async-Task), которые были определены в двух отдельных классах, таких как

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

которые инициализируются и выполняются в 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
        } 


    }

}

Теперь в приведенном выше коде MainClass.this хранится как ссылка на интерфейс в подклассах AsynTask, например,

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 каждого класса или подкласса AsynTask, JSONArray возвращается или передается обратно вызывающему классу, показанному ниже. В этом случае вызывающий класс MainClass, но есть другие классы активности, которые используют те же классы AsynTask (GetBeaconsList и GettingAirports)

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

Теперь у меня есть один метод (JsonArrayLoaded) в MainClass, чтобы решить два ответа, исходящих из двух разных фоновых задач или служб. Я использую условие, чтобы выяснить, какой сервис/класс или AsynTask выполняется.

Но я прошу наилучшего способа решить такой сценарий, как если бы у нас было 5 или более фоновых сервисов в будущем, и они просто возвращают массив JSON, поэтому мне нужно создавать отдельные интерфейсы для каждой службы?

Что должно быть объектно-ориентированным выходом в этом случае?

Ответ 1

Самое упрощенное решение, о котором я могу думать, - это изменить ваш интерфейс DelegateTaskCompleted так, чтобы он выглядел следующим образом:

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

Затем ваш onPostExecute отправит себя назад, как показано ниже:

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

Наконец, в вашем MainClass вы можете получить условную проверку на основе типа 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
         }

    }

Таким образом, вы можете легко идентифицировать AsyncTask, который отправляет через ответ, не отслеживая его, если он занимает больше времени, чем другой и т.д.


Кроме того, у вас есть другой класс, который расширяет AsyncTask, но добавляет абстрактную переменную для идентификации.

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
}

Затем используйте ваш аэропорт и маяк AsycTasks. Это потребует от них реализации метода getId.

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

А затем вместо выполнения условного if (task instanceof GettingAirports) вы можете сделать оператор switch, как показано ниже:

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

Надеюсь, что это поможет.

Ответ 2

Привет, этот код поможет вам

Это интерфейс для обратного вызова

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

}

использовать класс Asynctask как абстрактный класс

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

И в вашем коде используйте это как

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);

вы можете повторно использовать код таким образом, я надеюсь, что это вам поможет. Спасибо заранее.

Ответ 3

Если я правильно понял вашу проблему, вы несколько раз расширили AsyncTask. Цель каждого из этих подклассов - передать JSONArray в Activity, который реализует DelegateTaskCompleted, где вы будете что-то делать с ним. Задача состоит в том, что "что-то", что вы хотите сделать с этим JSONArray, отличается в зависимости от того, какой AsyncTask сгенерировал его.

Исходя из этих предположений, существует много разных способов, которыми вы можете отличить, от AsyncTask от JSONArray:

  • Создайте статическую переменную, такую ​​как int, в файле класса DelegateTaskCompleted для каждого типа JSONArray, который необходимо обработать. Добавьте параметр в JsonArrayLoaded того же типа этой переменной. Затем используйте ваши инструкции if-else или оператор switch, которые проверяют эту переменную на набор и выполняют действия на основе вашего JSONArray.
  • Если у вас есть доступ к тому, что генерирует JSONArray, сделайте индекс 0 массива содержащим информацию о том, как его анализировать. (Возможно, вы можете сравнить с if-else или коммутатором)
  • Как вы предположили, создание отдельного интерфейса для каждой AsyncTask или, альтернативно, одного интерфейса с несколькими методами.

Только опция 3 является объектно-ориентированным решением и, как было отмечено в комментариях, не является большой из-за масштабируемости. Это далеко не полный список, только некоторые из моих идей.

Мне интересно, хотя, стоит ли использовать интерфейсы вообще или, по крайней мере, в представленном порядке. Поскольку у вас уже есть разные подклассы AsyncTask для обработки генерации JSONArrays, почему бы не сделать то, что вы делаете с ними в методе doInBackground(), от основного потока или, по крайней мере, поместить эту логику где-нибудь в этих классах, и просто верните результаты (или, возможно, запишите их в базу данных и получите их при необходимости). Я думаю, что может быть лучший способ обработать ваше наследование AsyncTask, которое позволяет избежать взаимодействия с интерфейсами или, по крайней мере, использовать их по-разному, например, один интерфейс, реализуемый всеми вашими AsyncTasks.

Было бы очень полезно, если вы сможете уточнить свой вопрос и объяснить тип операций, выполняемых как AsyncTasks, так и ваш метод JsonArrayLoaded, и, возможно, ваши аргументы в пользу использования интерфейсов так, как вы. Трудно дать конкретный ответ OO или совет по лучшим практикам OO с такой небольшой информацией о том, что делает ваш код на самом деле, и надеется достичь.

Ответ 4

Вы также можете рассмотреть обработчик для достижения этого. Создайте обработчик в Activity, Передайте этот объект обработчика каждой AsyncTask. В onPost вызов handler.sendEmptyMessage(CONSTANT_INT); В Handler handleMessage check  msg.what в if или switch Таким образом, будет создан только один объект обработчика и будет использоваться в нескольких вызывает асинхронный вызов из одного действия.

Ответ 5

Добавьте одну переменную-член в оба класса AsyncTask i.e,

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

как

private int flag;

и записывать установщик для этого как

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

В 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();

В обоих классах AsyncTask пропускается флаг с помощью метода делегирования: -

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

Опять в MainClass для ответа: -

@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

Я предлагаю вам просто использовать n внутренних классов для своей деятельности, которые реализуют DelegateTaskCompleted. Это простой, эффективный, понятный и легко понятный (продуманный сервис) - и вы передаете делегат уже при создании своих AsyncTasks, так может быть, у вас уже был этот подход в вашем уме?

public class MainClass extends Activity {
    // probabnly not static ;)
    private final class BeaconsDelegate implements DelegateTaskCompleted ...
    private final class AirportsDelegate implements DelegateTaskCompleted ...
}