在 Android 和 Java 上复制 Swift 完成处理程序

Replicating Swift completion handler on Android & Java

多年后,我尝试使用 Firebase Firestore 开发一个 Android 应用程序。我基本上是在尝试复制这个 Swift 函数:

func getCategories(onCompletion completionBlock: @escaping (_ categories: [Category]?, _ error: Error?) -> Void) {

  firestore.collection("cats").getDocuments { (snap, error) in
    guard let snap = snap else {
      completionBlock(nil, error ?? anUnknownError)
      return
    }

    var categories: [Category] = []
    for document in snap.documents {
        let cat = Category.init(data: document.data())
        categories.append(cat)
    }
    completionBlock(categories, nil)
  }
}

但是我不知道swift的方块相当于什么,甚至不知道它是否存在

我检查了 Firebase 源代码。 Query.get() returns Task<QuerySnapshot> 所以我尝试 return a Task<List<Category>> 但运气不好。

有帮助吗?谢谢。

编辑:Android 添加代码以阐明我正在尝试做的事情。

public class FirestoreService {

    private static volatile FirestoreService singleton = new FirestoreService();

    public static FirestoreService getInstance() {
        return singleton;
    }

    private FirebaseFirestore firestore() {
        // default firestore instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();

        // default firestore settings
        FirebaseFirestoreSettings settings = db.getFirestoreSettings();

        // firestore settings builder
        FirebaseFirestoreSettings.Builder builder = new FirebaseFirestoreSettings.Builder(settings);

        // enable timstamps
        builder.setTimestampsInSnapshotsEnabled(true);

        // set new settings to db instance
        db.setFirestoreSettings(builder.build());


        // return db with new settings.
        return db;
    }



    public void getProductCategories(Handler? handler) {

       Task<QuerySnapshot> task = firestore().collection("coll").get();
       task.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            try {
                if (task.isSuccessful()) {
                    List<Category> cats = new ArrayList<>();
                    for (QueryDocumentSnapshot doc : task.getResult()) {
                        String id = doc.getId();
                        Map<String, Object> data = doc.getData();
                        Category cat = new Category(id, data);
                        cats.add(cat);
                    }
                    // now I need completion handler
                } else {
                    Log.w("ERROR", "Error getting categories", task.getException());
                }
            } catch (Exception e) {
                Log.e("ERROR", e.getMessage());
            }
        }
    });
    }

}



public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FirestoreService.getInstance().getCategories().addCompletionListener(
            // handle List<Category> and respresent in UI
        );
    }
}

使用 AsyncTask

您可以使用 AsyncTask。它有 3 个步骤。

1. onPreExecute() - 在运行宁doInBackground()之前你想做的事情。这发生在 UI 主线程中。

2. doInBackground()- AsyncTask,将在后台线程中执行操作(后台线程由Android 所以你不必担心)。

3.onPostExecute() - 在这里您可以从 doInBackground 方法接收任何数据。 postExecute方法再次执行,在UI主线程

因此您可以在 doInBackground() 中执行任何 I/O 操作,并且 return 您从服务器或任何其他数据源接收到的值 onPostExecute() 是相当于 swift.

中的完成块

如何申报

要使用 AsyncTask,您需要扩展 Android AsyncTask

因此您自己的 AsyncTask 声明将如下所示:

private class MyAsyncTask extends AsyncTask<Void, Void, Void> { ... }

您问的 3 个通用参数是什么?

1. Params - 执行时发送给任务的参数类型。

2. Progress - 在后台计算期间发布的进度单位的类型。 (几乎总是 Void,除非你关心操作的实际进度。注意这是 Void 带有大写字母,而 而不是 void 作为 return 类型)。

3. Result - 后台计算结果的类型。

完整示例

private class LongOperation extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... params) {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.interrupted();
                }
            }
            return "Executed";
        }

        @Override
        protected void onPostExecute(String result) {
            TextView txt = findViewById(R.id.output);
            txt.setText(result); 
        }
    }

在这个例子中,我创建了一个假的、长时间的操作,你不能 运行 UI 主线程(因为它是一个阻塞操作)。

操作完成后,return是一个String同样StringonPostExecute() 方法(记住,onPostExecute() 运行s 再次在 UI 主线程上)。因此,您可以将 UI 更改为您从长阻塞操作中收到的字符串值。

如果你想要文档,这里是:

https://developer.android.com/reference/android/os/AsyncTask

使用观察者模式

您也可以根据自己的情况使用观察者模式。

创建一个接口,它有一个方法onSuccess().让一个对象实现那个接口,当你需要它的时候,你可以调用onSuccess()方法。

示例:

public Interface SuccessInterface{
   void onSuccess()
}

public class SuccessHandler implements SuccessInterface{
   public void onSuccess(){
         //success code goes here
   }

}

然后在您的代码中实例化 SucessHandler,并在需要时调用 onSuccess()

非常感谢四位的帮助和领导@Daniel-b。

我现在已经解决了我的问题。

首先我创建了一个用于处理结果的接口;按照你的建议。

public interface ResultHandler<T> {
    void onSuccess(T data);
    void onFailure(Exception e);
}

然后在服务 class 中,我将 ResultHandler 添加到函数的输入参数中:

public void getUserInfo(String id, ResultHandler<UserInfo> handler) {
    firestore().collection("userInfo").document(id).get().addOnCompleteListener(snap -> {
        if (snap.isSuccessful()) {
           try {
               // failable constructor. use try-catch
               UserInfo info = new UserInfo(snap.getResult().getId(), snap.getResult().getData());
               handler.onSuccess(info);
           } catch (Exception e) {
                handler.onFailure(e);
           }
        } else {
            handler.onFailure(snap.getException())
        }
    });
}

并在 Activity

调用了服务
FirestoreService.getInstance().getUserInfo("ZsrAdsG5HVYLTZDBeZtkGDlIBW42", new ResultHandler<UserInfo>() {
    @Override
    public void onSuccess(UserInfo data) {
        Log.i("UserInfo", data.id);                    
    }

    @Override
    public void onFailure(Exception e) {
        // getting data failed for some reason
    }
});

对于API 26, CompletionHandler 可用。 检查 https://developer.android.com/reference/java/nio/channels/CompletionHandler