Android如何将iOS中的异步任务组合在一起

OMG*_*POP 27 java android ios android-asynctask swift

我在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)

        }

    }
}
Run Code Online (Sandbox Code Playgroud)

正如你从我的代码中看到的那样,我获取所有comments相同的内容article,然后replies在每个下面获取相应的内容comment.完成所有请求后,我调用我的success回调.这可以使用GCD实现dispatch_group.

现在我将相同的功能迁移到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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,我使用的success是在我获得所有内容之后立即执行comments,并且在获得所有内容之前执行replies.

那么如何对它们进行分组并延迟响应呢?

我正在研究毛茸茸的实现

taskCount++;
if (taskCount == totalCount) {
    success.run();
} 
Run Code Online (Sandbox Code Playgroud)

在回复块,但似乎非常繁琐.

Dam*_*aca 21

您可以使用我为模仿iOS行为而创建的这个类来完成它.调用enter()和leave(),就像你在iOS中使用dispatch_group_enter和dispatch_group_leave一样,并在你想要分组的请求之后调用notify(),就像dispatch_group_notify一样.它也像iOS使用块一样使用runnable:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你 ;)


Ram*_*aja 5

这是Damien Praca的答案的Kotlin版本。这样您就可以像这样使用Kotlin lambda。

val dispatchGroup = DispatchGroup()
dispatchGroup.enter()
// Some long running task
dispatchGroup.leave()

dispatchGroup.notify {
// Some code to run after all dispatch groups complete
}

class DispatchGroup {
    private var count = 0
    private var runnable: (() -> Unit)? = null

    init {
        count = 0
    }

    @Synchronized
    fun enter() {
        count++
    }

    @Synchronized
    fun leave() {
        count--
        notifyGroup()
    }

    fun notify(r: () -> Unit) {
        runnable = r
        notifyGroup()
    }

    private fun notifyGroup() {
        if (count <= 0 && runnable != null) {
            runnable!!()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,我鼓励您添加超时安全性,以避免在不满足leave()条件时被阻止。 (2认同)

Erc*_*can 3

您可以使用Threads 和Thread.join()with Handlers 作为选项。

引用自: https: //docs.oracle.com/javase/tutorial/essential/concurrency/join.html

join 方法允许一个线程等待另一个线程的完成。如果 t 是一个 Thread 对象,其线程当前正在执行,

t.join(); 导致当前线程暂停执行,直到 t 的线程终止。join 的重载允许程序员指定等待时间。但是,与 sleep 一样,join 依赖于操作系统的计时,因此您不应假设 join 将完全等待您指定的时间。

与 sleep 一样,join 通过退出并抛出 InterruptedException 来响应中断。

编辑:您还应该检查我的事件调度程序要点。你可能会喜欢它。