Первое, что я хотел бы сказать, это то, что, по моему мнению, n-уровневая архитектура, которую вы описываете, немного излишня для большинства мобильных приложений.Это не значит, что вам не нужно разделять свое приложение и разделять обязанности.Просто уровни, которые вы описываете, действительно являются хорошими архитектурными уровнями для крупных корпоративных приложений, но я считаю, что применение этих уровней строго на основе кода Android приводит к борьбе с системой, когда на самом деле есть (лучший) способ сделать это для Android.
Например, одна из ваших проблем заключается в том, что вы хотели бы полностью отделить «службу» от своей деятельности, но все же хотите обновить что-то в пользовательском интерфейсе.Это невозможно.
Android широко использует внедрение зависимостей.Вы заметите, что Context часто является первым аргументом для различных методов.Просто чтобы показать, что если вы хотите полностью отделить что-то от пользовательского интерфейса, вам нужно создать новый «контекст» для работы.Android предоставляет это с услугами.Таким образом, вы можете работать полностью отдельно от пользовательского интерфейса и использовать намерения для обмена сообщениями между фоновой службой и пользовательским интерфейсом.
Но я понимаю, что для некоторых приложений или начинающих разработчиков Android службы кажутся немного сложными (они не являютсядействительно).Просто хотел отметить, что сервисы - это единственный реальный способ создания потока, который не связан с деятельностью.Некоторые люди используют трюки, переопределяя класс Application и отображая мягкие ссылки на действия и потоки.Таким образом, когда происходят изменения конфигурации (например, изменение ориентации), потоки не уничтожаются и могут получить ссылку на вновь созданный экземпляр действия.Эти трюки, на мой взгляд, являются анти-шаблонами.
Возвращаясь к вашей проблеме.
Я предлагаю сделать это простым.Просто знайте, что запуск нового потока из пользовательского интерфейса подразумевает, что поток может быть убит при изменении конфигурации, и вы можете потерять данные, уже извлеченные из сети.
- Напишите класс утилиты http, который переносит некоторые записи /получить функциональность и, возможно, установить некоторые заголовки http для каждого запроса.
- Написать простой слой обслуживания.Эти классы содержат методы, каждый из которых выполняет одну простую задачу или запрос покоя.
- В своей деятельности используйте AsyncTask, который объединяет некоторые методы обслуживания и обеспечивает обратную связь с пользовательским интерфейсом
Вы можете улучшитьоб этом позже, если вам нравится перемещать логику из AsyncTask в ее собственную реальную фоновую службу и выполнять промежуточные сообщения с помощью Intents и BroadcastReceivers.
Но для вашего удобства приведен упрощенный пример того, как сделать это простым способом без служб:
public class OrderActivity extends Activity {
private ProgressDialog progressDialog = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new OrderLoaderTask().execute();
}
class Order {
// Add some data
}
class OrderService {
public List<Integer> getOrderIds() {
List<Integer> ids = Arrays.asList(new Integer[] {1, 2, 3, 4, 5, 6, 7});
return ids;
}
public Order getOrder(int id) {
// Do real http request through some utility class
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new Order();
}
}
class OrderLoaderTask extends AsyncTask<Void, Integer, List<Order>> {
@Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(TestAndroidActivity.this, "loading", "loading");
}
@Override
protected void onProgressUpdate(Integer... values) {
progressDialog.setMessage(String.format("loading (%s/%s)", values[0], values[1]));
}
@Override
protected List<Order> doInBackground(Void... params) {
OrderService service = new OrderService();
List<Order> orders = new ArrayList<Order>();
List<Integer> ids = service.getOrderIds();
for (int i=0; i<ids.size(); i++) {
orders.add(service.getOrder(ids.get(i)));
publishProgress(i+1, ids.size());
}
return orders;
}
@Override
protected void onPostExecute(List<Order> result) {
if (result != null) {
// Do something with the results!
}
progressDialog.dismiss();
}
}
}
Примечание: просто создайте новый проект Android, скопируйте этот код, исправьте импорт и запустите!
Если вы хотите «повторно использовать» код в AsyncTask, перейдите в его собственный файл, сделайте класс общедоступным и переопределите методы ... Опять же, между потоками всегда необходим некоторый связующий код или интерфейс.
new OrderLoaderTask() {
protected void onProgressUpdate(Integer[] values) {
// Update progress
};
protected void onPostExecute(List<Order> result) {
// Do something
};
}.execute();