firebase存储java.lang.IllegalStateException:任务尚未完成

1 android illegalstateexception firebase firebase-storage

我想从 android 上的 firebase 文件夹下载所有文件。

这是我的代码

try {
        StorageReference reference = storage.getReference().child("Ringtone");
    reference.listAll().addOnCompleteListener(new OnCompleteListener<ListResult>() {
        @Override
        public void onComplete(@NonNull Task<ListResult> task) {
            if (task.isComplete()){
            task.addOnSuccessListener(new OnSuccessListener<ListResult>() {    /////line 82  == 1st line where i am getting error
                @Override
                public void onSuccess(ListResult listResult) {
                    for (StorageReference item : listResult.getItems()) {

                        RingtoneModel ringtoneModel = new RingtoneModel();
                        ringtoneModel.setUri(item.getDownloadUrl().getResult());      /////line 88 == 2nd line where i am getting  error here
                        item.getMetadata().addOnSuccessListener(new OnSuccessListener<StorageMetadata>() {
                            @Override
                            public void onSuccess(StorageMetadata storageMetadata) {
                                ringtoneModel.setSongName(storageMetadata.getName());
                                Toast.makeText(MainActivity.this, "ring name saved", Toast.LENGTH_SHORT).show();
                            }
                        }).addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
                                Log.e("metadata error",e.getMessage());
                            }
                        });
                    }
                }
            });}else {
                Toast.makeText(MainActivity.this, (CharSequence) task.getException(), Toast.LENGTH_SHORT).show();
            }
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Log.e("list all error",e.getMessage());
        }
    }); }catch (Exception e){
        Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
        Log.e("all errors",e.getMessage());}
}
Run Code Online (Sandbox Code Playgroud)

Logcat错误消息

   /com.example.alarm E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.example.alarm, PID: 433
        java.lang.IllegalStateException: Task is not yet complete
            at com.google.android.gms.common.internal.Preconditions.checkState(Unknown Source)
            at com.google.android.gms.tasks.zzu.zzb(Unknown Source)
            at com.google.android.gms.tasks.zzu.getResult(Unknown Source)
            at com.example.alarm.MainActivity$3.onSuccess(MainActivity.java:88)
            at com.example.alarm.MainActivity$3.onSuccess(MainActivity.java:82)
Run Code Online (Sandbox Code Playgroud)

我的文件夹和文件在 firebase 数据库中的路径 Firebase storage >Rington<my files

<--我尝试过的 --> 我尝试添加 addonsuuccesslistner 、 addoncompletelitner、task.isComplete()、task.issuccessfull() 以及更多内容

sam*_*man 5

虽然addOnSuccessListeneraddOnFailureListener对于处理异步任务的结果很有用,但当您需要像这里一样将事物链接在一起时,它们并不是很有用。

查看您的代码,您调用以下行:

StorageReference item;

item.getDownloadUrl().getResult()
Run Code Online (Sandbox Code Playgroud)

抛出您得到的异常是因为您在调用之前没有等待此任务完成getResult()

Task<String> downloadUrlTask = item.getDownloadUrl();

downloadUrlTask
  .addOnSuccessListener(result -> {
    // now do something with result
  })
  .addOnFailureListener(e -> {
    // now do something with the exception
  });
Run Code Online (Sandbox Code Playgroud)

虽然如果这就是您所需要的,上面的代码很有帮助,但您要做的是等待它完成,getMetadata()以便您可以创建类的实例RingtoneModel


这就是Tasks实用程序类的用武之地。

Tasks.whenAll(Collection<Task<?>> tasks)只有当所有任务都tasks成功完成时才会成功。

Task<String> downloadUrlTask = item.getDownloadUrl();
Task<StorageMetadata> metadataTask = item.getMetadata();

return Tasks
    .whenAll([ // wait for these tasks to finish successfully
        downloadUrlTask,
        metadataTask
    ])
    .addOnSuccessListener(() -> { // then assemble its RingtoneModel
        RingtoneModel ringtoneModel = new RingtoneModel();
        ringtoneModel.setUri(downloadUrlTask.getResult());
        ringtoneModel.setSongName(metadataTask.getResult().getName());

        // we've now got a RingtoneModel! but what to do with it?
    });
Run Code Online (Sandbox Code Playgroud)

而不是addOnSuccessListener()在上面的代码中使用,如果我们使用,onSuccessTask()我们可以返回RingtoneModel后面,这样Task<void>fromTasks.whenAll()现在是一个Task<RingtoneModel>. 为此,我们需要使用Tasks.forResult()which 将我们的RingtoneModel并将其转换为Task<RingtoneModel>.

// function that takes a StorageReference and
// returns a task that resolves to a RingtoneModel
StorageReference item -> {
    Task<String> downloadUrlTask = item.getDownloadUrl();
    Task<StorageMetadata> metadataTask = item.getMetadata();

    return Tasks
        .whenAll([ // wait for these tasks to finish successfully
            downloadUrlTask,
            metadataTask
        ])
        .onSuccessTask(() -> { // then assemble its RingtoneModel
            RingtoneModel ringtoneModel = new RingtoneModel();

            // because these task have finished by now,
            // you can safely use getResult() here
            ringtoneModel.setUri(downloadUrlTask.getResult());
            ringtoneModel.setSongName(metadataTask.getResult().getName());

            return Tasks.forResult(ringtoneModel);
        });
}
Run Code Online (Sandbox Code Playgroud)

现在我们已经有了 a RingtoneModelfor one StorageReference,我们想把 a 变成List<StorageReference>a List<RingtoneModel>。我们可以使用以下方法来做到这一点

List<Task<RingtoneModel>> getRingtoneTasks = listResult.getItems()
    .stream()
    .map(convertToRingtoneModel); // the function above
Run Code Online (Sandbox Code Playgroud)

请注意,这里我们用List<Task<RingtoneModel>>的是Task<List<RingtoneModel>>. 为了扭转这个局面,我们再次使用Tasks.whenAll()onSuccessTask()、。stream().map()Tasks.forResult()

return Tasks
    .whenAll(getRingtoneTasks)
    .onSuccessTask(() -> {
        return Tasks.forResult(
            getRingtoneTasks
                .stream()
                .map(task -> task.getResult());
        );
    });
Run Code Online (Sandbox Code Playgroud)

现在,您可能会看到上面的块,并认为这是一个非常简洁的实用方法,您是对的,因为您可以使用它来执行相同的操作:

return Tasks.whenAllSuccess(getRingtoneTasks);
Run Code Online (Sandbox Code Playgroud)

将所有这些混合在一起,得到:

public Task<List<RingtoneModel>> getRingtones() {
    StorageReference reference = storage.getReference().child("Ringtone");
    return reference.listAll() // find all objects under /Ringtone
        .onSuccessTask(listResult -> {
            // for each item found, assemble a RingtoneModel
            List<Task<RingtoneModel>> getRingtoneTasks = listResult.getItems()
                .stream()
                .map((item) -> {
                    // A RingtoneModel needs the download URL and the object's metadata
                    Task<String> downloadUrlTask = item.getDownloadUrl();
                    Task<StorageMetadata> metadataTask = item.getMetadata();

                    return Tasks
                        .whenAll([ // wait for these tasks to finish successfully
                            downloadUrlTask,
                            metadataTask
                        ])
                        .onSuccessTask(() -> { // then assemble the RingtoneModel and return it
                            RingtoneModel ringtoneModel = new RingtoneModel();
                            ringtoneModel.setUri(downloadUrlTask.getResult());
                            ringtoneModel.setSongName(metadataTask.getResult().getName());
                            return Tasks.forResult(ringtoneModel);
                        });
                });

            return Tasks.whenAllSuccess(getRingtoneTasks);
        });
}
Run Code Online (Sandbox Code Playgroud)

然后,当您想要获取云存储中的所有铃声时,您只需要:

getRingtones()
    .addOnSuccessListener(ringtoneModelList -> {
        Toast.makeText(MainActivity.this, "Found " + ringtoneModelList.size() + " ringtones.", Toast.LENGTH_SHORT).show();
        // I recommend storing ringtoneModelList in your database of choice
    })
    .addOnFailureListener(e -> {
        Toast.makeText(MainActivity.this, "Failed to get any ringtones.", Toast.LENGTH_SHORT).show();
        Log.e("getRingtones error", e); // <-- log the full error to help with debugging
    });
Run Code Online (Sandbox Code Playgroud)