Intereting Posts
Почему я не могу установить currentTime, и продолжительность равна 0 в HTML AudioElement в Android WebView? Плагин android eclipse не может найти допустимые пути Android, Scala и Proguard Фрагмент Загрузка транзакции пустой, но фрагмент показан после вращения устройства Как написать мертвую простую программу SERVER SERVER (не приложение) для Android-устройств? Как добавить разделители и пробелы между элементами в RecyclerView? Android: OnTouch, MotionEvent.ACTION_MOVE не распознается? Можно загружать только определенные строки кода в соответствии с версией ОС Android? Android. Отображать контакты в виде списка Android 6.0 Marshmallow: странная ошибка с анимацией фрагментов Могу ли я установить FLAG_LAYOUT_NO_LIMITS только для строки состояния? Как установить фиксированное количество строк в android gridView? Добавление моего пользовательского представления в XML-макет вызывает исключение Как заставить редактирование EditText выполнять в полноэкранном режиме? Протоколы SSL / TLS и комплекты шифров с AndroidHttpClient

Android, как группировать задачи async вместе, как в iOS

У меня есть функция в приложении iOS, которая использует dispatch_group для группировки нескольких запросов на отдых:

 static func fetchCommentsAndTheirReplies(articleId: String, failure: ((NSError)->Void)?, success: (comments: [[String: AnyObject]], replies: [[[String: AnyObject]]], userIds: Set<String>)->Void) { var retComments = [[String: AnyObject]]() var retReplies = [[[String: AnyObject]]]() var retUserIds = Set<String>() let queue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0) Alamofire.request(.GET, API.baseUrl + API.article.listCreateComment, parameters: [API.article.articleId: articleId]).responseJSON { response in dispatch_async(queue) { guard let comments = response.result.value as? [[String: AnyObject]] else { failure?(Helper.error()) return } print(comments) retComments = comments let group = dispatch_group_create() for (commentIndex, comment) in comments.enumerate() { guard let id = comment["_id"] as? String else {continue} let relevantUserIds = helperParseRelaventUserIdsFromEntity(comment) for userId in relevantUserIds { retUserIds.insert(userId) } retReplies.append([[String: AnyObject]]()) dispatch_group_enter(group) Alamofire.request(.GET, API.baseUrl + API.article.listCreateReply, parameters: [API.article.commentId: id]).responseJSON { response in dispatch_async(queue) { if let replies = response.result.value as? [[String: AnyObject]] { for (_, reply) in replies.enumerate() { let relevantUserIds = helperParseRelaventUserIdsFromEntity(reply) for userId in relevantUserIds { retUserIds.insert(userId) } } retReplies[commentIndex] = replies } dispatch_group_leave(group) } } } dispatch_group_wait(group, DISPATCH_TIME_FOREVER) success(comments: retComments, replies: retReplies, userIds: retUserIds) } } } 

Как вы можете видеть из моего кода, я извлекаю все comments в одной и той же article , а затем получаю replies по каждому comment . После того, как все запросы выполнены, я вызываю свой обратный вызов. Этого можно достичь с помощью dispatch_group GCD.

Теперь я переношу те же функции в Android.

 public static void fetchCommentsAndTheirReplies(Context context, String articleId, final StringBuffer outErrorMessage, final Runnable failure, final ArrayList<JSONObject> outComments, final ArrayList<ArrayList<JSONObject>> outReplies, final HashSet<String> outUserIds, final Runnable success) { final RequestQueue queue = Volley.newRequestQueue(context); HashMap<String, String> commentParams = new HashMap<>(); commentParams.put(API.article.articleId, articleId); JsonArrayRequest commentRequest = new JsonArrayRequest(Request.Method.GET, API.baseUrl + API.article.listCreateComment, new JSONObject(commentParams), new Response.Listener<JSONArray>() { @Override public void onResponse(JSONArray response) { try { for (int i = 0; i < response.length(); i++) { JSONObject comment = response.getJSONObject(i); outComments.add(comment); outUserIds.addAll(helperParseRelaventUserIdsFromEntity(comment)); outReplies.add(new ArrayList<JSONObject>()); //TODO: DISPATCH_GROUP? String id = comment.getString("_id"); HashMap<String, String> replyParams = new HashMap<>(); replyParams.put(API.article.commentId, id); final int finalI = i; JsonArrayRequest replyRequest = new JsonArrayRequest(Request.Method.GET, API.baseUrl + API.article.listCreateReply, new JSONObject(replyParams), new Response.Listener<JSONArray>() { @Override public void onResponse(JSONArray response) { try { for (int j = 0; j < response.length(); j++) { JSONObject reply = response.getJSONObject(j); outUserIds.addAll(helperParseRelaventUserIdsFromEntity(reply)); outReplies.get(finalI).add(reply); } } catch (JSONException ex) {} } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) {} }); queue.add(replyRequest); } success.run(); } catch (JSONException ex) {} } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { outErrorMessage.append(error.getMessage()); failure.run(); } }); queue.add(commentRequest); } 

Обратите внимание, что я использую success , выполняется сразу после получения всех comments и до получения всех replies .

Итак, как я могу группировать их и откладывать ответ?

Я работаю над волосатой реализацией, как

 taskCount++; if (taskCount == totalCount) { success.run(); } 

В блоке ответа, но это кажется очень утомительным.

Solutions Collecting From Web of "Android, как группировать задачи async вместе, как в iOS"

Прямого аналога dispatch_group в простой Java или Android нет. Я могу порекомендовать несколько довольно сложных методов для создания действительно чистого и элегантного решения, если вы готовы вложить в него дополнительное время. К сожалению, это не будет одна или две строки кода.

  1. Используйте RxJava с распараллеливанием . RxJava обеспечивает чистый способ отправки нескольких задач, но по умолчанию он работает последовательно. См. Эту статью, чтобы одновременно выполнять задачи.

  2. Хотя это не совсем то, что вам нужно, вы можете попробовать ForkJoinPool выполнить свою группу задач и получить после себя один результат.

Вы можете просто сделать это с помощью этого класса, который я сделал, чтобы имитировать поведение iOS. Вызовите enter () и оставьте () так же, как вы делали в iOS, с dispatch_group_enter и dispatch_group_leave и вызывают notify () сразу после запросов, которые вы хотите сгруппировать, точно так же, как dispatch_group_notify. Он также использует runnable так же, как iOS использует блоки:

 public class DispatchGroup { private int count = 0; private Runnable runnable; public DispatchGroup() { super(); count = 0; } public synchronized void enter(){ count++; } public synchronized void leave(){ count--; notifyGroup(); } public void notify(Runnable r) { runnable = r; notifyGroup(); } private void notifyGroup(){ if (count <=0 && runnable!=null) { runnable.run(); } } } 

Надеюсь, поможет 😉

Ваша «волосатая» реализация не «волосатая» во всех имхо.

 public void onResponse(JSONArray response) { try { final int[] taskFinished = {0}; final int taskTotal = response.length(); for (int i = 0; i < response.length(); i++) { JSONObject comment = response.getJSONObject(i); outComments.add(comment); outUserIds.addAll(helperParseRelaventUserIdsFromEntity(comment)); outReplies.add(new ArrayList<JSONObject>()); //TODO: DISPATCH_GROUP? String id = comment.getString("_id"); HashMap<String, String> replyParams = new HashMap<>(); replyParams.put(API.article.commentId, id); final int finalI = i; JsonArrayRequest replyRequest = new JsonArrayRequest(Request.Method.GET, API.baseUrl + API.article.listCreateReply, new JSONObject(replyParams), new Response.Listener<JSONArray>() { @Override public void onResponse(JSONArray response) { taskFinished[0]++; try { for (int j = 0; j < response.length(); j++) { JSONObject reply = response.getJSONObject(j); outUserIds.addAll(helperParseRelaventUserIdsFromEntity(reply)); outReplies.get(finalI).add(reply); } } catch (JSONException ex) {} if (taskFinished[0] == taskTotal) { success.run(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { taskFinished[0]++; if (taskFinished[0] == taskTotal) { success.run(); } } }); queue.add(replyRequest); } } catch (JSONException ex) {} } 

Вы можете использовать Thread s и Thread.join() с Handler s в качестве опции.

Цитата из: https://docs.oracle.com/javase/tutorial/essential/concurrency/join.html

Метод join позволяет одному потоку ждать завершения другого. Если t – объект Thread, поток которого в настоящее время выполняется,

t.join (); Заставляет текущий поток приостанавливать выполнение до тех пор, пока поток t не завершится. Перегрузки соединения позволяют программисту указать период ожидания. Однако, как и со сном, соединение зависит от ОС для синхронизации, поэтому вы не должны предполагать, что соединение будет ждать столько, сколько вы укажете.

Как и сон, соединение реагирует на прерывание, выходя из InterruptedException.

EDIT : вы также должны проверить мой диспетчер событий . Вам это может понравиться.

Попробуйте очередь приоритетов: https://github.com/yigit/android-priority-jobqueue

Приоритетная очередность заданий – это реализация очереди заданий, специально написанной для Android, для легкого планирования заданий (задач), выполняющихся в фоновом режиме, повышения стабильности UX и приложений.

(…)

Вы можете группировать задания, чтобы обеспечить их последовательное выполнение, если это необходимо. Например, предположим, что у вас есть клиент обмена сообщениями, и ваш пользователь отправил кучу сообщений, когда у их телефона не было сетевого покрытия. При создании этих заданий SendMessageToNetwork вы можете группировать их по идентификатору беседы. Благодаря такому подходу сообщения в одной и той же цепочке отправляются в том порядке, в котором они были помещены в очередь, в то время как сообщения между различными цепочками сообщений все равно отправляются параллельно. Это позволяет без труда максимизировать использование сети и обеспечивать целостность данных.

Не использовать Java

Попросите Котлина попробовать, у него есть обещания

 task { //some (long running) operation, or just: 1 + 1 } then { i -> "result: $i" } success { msg -> println(msg) } 

https://github.com/mplatvoet/kovenant

Вам не нужно, но самый простой способ решить эту проблему – использовать модификацию с rxJava вместо volley.

Возможно, вы ищете что-то вроде Retrofit или Volley .