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

firebase storage java.lang.IllegalStateException: Task is not yet complete

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

this is my code

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());}
}

Logcat error message

   /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.onSuccess(MainActivity.java:88)
            at com.example.alarm.MainActivity.onSuccess(MainActivity.java:82)

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

<--我试过的--> 我尝试添加 addonsuuccesslistner , addoncompletelitner, task.isComplete(), task.issuccessfull() 以及更多东西

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

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

StorageReference item;

item.getDownloadUrl().getResult()

你得到的异常被抛出是因为你在调用 getResult().

之前没有等待这个任务完成
Task<String> downloadUrlTask = item.getDownloadUrl();

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

虽然上面的代码很有用,如果这就是您所需要的,您要做的是等待它与 getMetadata() 一起完成,这样您就可以创建 RingtoneModel class.


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

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?
    });

而不是在上面的代码中使用 addOnSuccessListener(),如果我们使用 onSuccessTask() we can return the RingtoneModel back so that the Task<void> from Tasks.whenAll() is now a Task<RingtoneModel>. To do this, we need to use Tasks.forResult(),它将把我们的 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);
        });
}

现在我们有一个 StorageReferenceRingtoneModel,我们想把 List<StorageReference> 变成 List<RingtoneModel>。我们可以使用

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

注意这里我们有 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());
        );
    });

现在您可能会看到上面的那个块,并认为这是一个非常巧妙的方法,可以用作实用方法,您是对的,因为您可以使用它来做同样的事情:

return Tasks.whenAllSuccess(getRingtoneTasks);

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

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);
        });
}

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

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
    });