Android Firebase如何在将图像上传到数据库之前等待上传完成?

huangapple 未分类评论43阅读模式
英文:

Android Firebase How to wait for image upload before registering to database?

问题

以下是已经翻译好的部分:

我刚接触 Android 开发,遇到了一个问题。

我有一个片段,用户可以在其中发布公告,并可以选择性地上传照片。
当表单填写完整并按下“发布公告”按钮时,我会触发保存信息到数据库的方法。

我面临的唯一问题是获取新上传照片的 Uri。
以下是提取信息的代码。

public Map<String, Object> appendDataFromAnnouncementForm() {
    String title = titleLineEdit.getText().toString();
    String category = categoryLineEdit.getText().toString();
    String description = descriptionLineEdit.getText().toString();
    String date = dateLineEdit.getText().toString();
    String time = timeLineEdit.getText().toString();
    String location = locationLineEdit.getText().toString();

    // 将图片上传到 Firebase 并获取 Uri

    if (localPhotoUri != null) {
        uploadImageToFirebase(generatePhotoName(localPhotoUri), localPhotoUri);
    }

    Map<String, Object> newAnnouncement = new HashMap<>();

    if (uploadedImageUri != null) {
        newAnnouncement.put("imageUri", uploadedImageUri.toString());
    }

    newAnnouncement.put("title", title);
    newAnnouncement.put("category", category);
    newAnnouncement.put("description", description);
    newAnnouncement.put("date", date);
    newAnnouncement.put("time", time);
    newAnnouncement.put("location", location);

    return newAnnouncement;
}

下面是将照片上传到 Firebase 存储的代码。

private void uploadImageToFirebase(String photoName, Uri localContentUri) {
    imagesStorageReferance = myStorageReference.child("images/" + photoName);
    imagesStorageReferance.putFile(localContentUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
            imagesStorageReferance.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                @Override
                public void onSuccess(Uri uri) {
                    Log.d(TAG, "onSuccess: 照片的下载链接是 " + uri.toString());
                    uploadedImageUri = uri;
                }
            });
        }
    })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    Log.d(TAG, "onFailure: 将照片上传到数据库失败 " + e.getMessage());
                }
            });
}

从我在互联网上阅读的内容来看,这是一个同步问题(基本上是在我的照片上传之前,应用程序就已经将信息注册到数据库中)。有很多解决方案,我已经尝试过很多,但实际上我找不到一个适用于我的情况的解决方案...

如果您能够为我提供一些解释,告诉我应该怎么做才能解决这个问题,我将不胜感激。我应该如何等待照片上传?

英文:

I am new to android development and I have an issue.

I have a fragment in which a user can post an announcement and should be able to upload a photo(optional).
When the form is full and the "Post announcement" button is pressed, I trigger the method to save the information to the database.

The only problem I am facing is retrieving the Uri of the newly uploaded photo.
This is the code which extracts the information.

public Map&lt;String, Object&gt; appendDataFromAnnouncementForm(){
    String title = titleLineEdit.getText().toString();
    String category = categoryLineEdit.getText().toString();
    String description = descriptionLineEdit.getText().toString();
    String date = dateLineEdit.getText().toString();
    String time = timeLineEdit.getText().toString();
    String location = locationLineEdit.getText().toString();

    //Image upload to firebase + getting the Uri

    if(localPhotoUri != null){
        uploadImageToFirebase(generatePhotoName(localPhotoUri), localPhotoUri);
    }


    Map&lt;String, Object&gt; newAnnouncement = new HashMap&lt;&gt;();

    //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    if(uploadedImageUri != null) // &lt;- this is always null
    {newAnnouncement.put(&quot;imageUri&quot;, uploadedImageUri.toString());}
    //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

    newAnnouncement.put(&quot;title&quot;, title);
    newAnnouncement.put(&quot;category&quot;, category);
    newAnnouncement.put(&quot;description&quot;, description);
    newAnnouncement.put(&quot;date&quot;, date);
    newAnnouncement.put(&quot;time&quot;, time);
    newAnnouncement.put(&quot;location&quot;, location);



    return newAnnouncement;
}

Below I am posting the code which uploads the photo to Firebase Storage. Since

private void uploadImageToFirebase(String photoName, Uri localContentUri) {
    imagesStorageReferance = myStorageReference.child(&quot;images/&quot; + photoName);
    imagesStorageReferance.putFile(localContentUri).addOnSuccessListener(new OnSuccessListener&lt;UploadTask.TaskSnapshot&gt;() {
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
            //getUploadedImageUri(referenceToImageFolder);
            imagesStorageReferance.getDownloadUrl().addOnSuccessListener(new OnSuccessListener&lt;Uri&gt;() {
                @Override
                public void onSuccess(Uri uri) {
                    Log.d(TAG, &quot;onSuccess: The download url of the photo is &quot;
                            + uri.toString());
                    uploadedImageUri = uri; /// &lt;- I want to retrieve this 
                }
            });

        }
    })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    Log.d(TAG, &quot;onFailure: Failed uploading the photo to the database &quot; + e.getMessage());
                }
            });
}

From what I have read on the Internet, this is an synchronization problem(basically, the app registers the information to the database before my photo is uploaded). There are many solutions which I have tried, but I can't really figure it out one to work on my case...

I would be very grateful if you could provide me some explanation on what I should do in order to fix this. How can I wait the photo to be uploaded ?

答案1

得分: 0

由于 Firebase 是异步工作的,代码会继续执行,无论 Firebase 是否已完成上传过程。在您的情况下,代码在调用上传后,继续执行的速度要快于上传到 Firebase 的时间,以至于在调用上传后直接检查 uploadedImageUri 时会得到空值,这解释了为什么您得到了空值。

为了解决这个问题,我建议您在 uploadImageToFirebase 函数内部,在 uploadedImageUri = uri; 后面的位置进行数据库注册,以确保在数据库注册之前始终可以获取到非空的 uploadedImageUri

private void uploadImageToFirebase(String photoName, Uri localContentUri) {
    imagesStorageReferance = myStorageReference.child("images/" + photoName);
    imagesStorageReferance.putFile(localContentUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
            imagesStorageReferance.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                @Override
                public void onSuccess(Uri uri) {
                    uploadedImageUri = uri;

                    String title = titleLineEdit.getText().toString();
                    String category = categoryLineEdit.getText().toString();
                    String description = descriptionLineEdit.getText().toString();
                    String date = dateLineEdit.getText().toString();
                    String time = timeLineEdit.getText().toString();
                    String location = locationLineEdit.getText().toString();

                    Map<String, Object> newAnnouncement = new HashMap<>();

                    newAnnouncement.put("imageUri", uploadedImageUri.toString());

                    newAnnouncement.put("title", title);
                    newAnnouncement.put("category", category);
                    newAnnouncement.put("description", description);
                    newAnnouncement.put("date", date);
                    newAnnouncement.put("time", time);
                    newAnnouncement.put("location", location);

                    // 在这里将 newAnnouncement 上传到 Firebase...
                }
            });

        }
    })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    Log.d(TAG, "onFailure: Failed uploading the photo to the database " + e.getMessage());
                }
            });
}
英文:

Since firebase works asynchronously, the code continues to execute regardless of whether firebase has finished the upload process or not. In your case, the time to run the code following firebase is faster than the upload time to firebase to eventually assign uploadedImageUri = uri; which explains why you are getting a null value for uploadedImageUri present directly after the call for upload.

For this matter, I would suggest you to register to database inside uploadImageToFirebase function after uploadedImageUri = uri; to ensure that uploadedImageUri is never null and always fetched before database registration.

private void uploadImageToFirebase(String photoName, Uri localContentUri) {
    imagesStorageReferance = myStorageReference.child(&quot;images/&quot; + photoName);
    imagesStorageReferance.putFile(localContentUri).addOnSuccessListener(new OnSuccessListener&lt;UploadTask.TaskSnapshot&gt;() {
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
            //getUploadedImageUri(referenceToImageFolder);
            imagesStorageReferance.getDownloadUrl().addOnSuccessListener(new OnSuccessListener&lt;Uri&gt;() {
                @Override
                public void onSuccess(Uri uri) {
                    Log.d(TAG, &quot;onSuccess: The download url of the photo is &quot;
                            + uri.toString());
                    uploadedImageUri = uri;
    String title = titleLineEdit.getText().toString();
    String category = categoryLineEdit.getText().toString();
    String description = descriptionLineEdit.getText().toString();
    String date = dateLineEdit.getText().toString();
    String time = timeLineEdit.getText().toString();
    String location = locationLineEdit.getText().toString();

    Map&lt;String, Object&gt; newAnnouncement = new HashMap&lt;&gt;();

    newAnnouncement.put(&quot;imageUri&quot;, uploadedImageUri.toString());

    newAnnouncement.put(&quot;title&quot;, title);
    newAnnouncement.put(&quot;category&quot;, category);
    newAnnouncement.put(&quot;description&quot;, description);
    newAnnouncement.put(&quot;date&quot;, date);
    newAnnouncement.put(&quot;time&quot;, time);
    newAnnouncement.put(&quot;location&quot;, location);

//UPLOAD newAnouncement TO FIREBASE HERE...
                }
            });

        }
    })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    Log.d(TAG, &quot;onFailure: Failed uploading the photo to the database &quot; + e.getMessage());
                }
            });
}

答案2

得分: 0

以下是代码的翻译部分:

private void uploadImage()
{
    if (imageUri != null)
    {
        final StorageReference reference = storageReference.child(System.currentTimeMillis() + "." + getExtension(imageUri));
        uploadTask = reference.putFile(imageUri);
        uploadTask.continueWithTask(new Continuation() {
            @Override
            public Object then(@NonNull Task task) throws Exception {
                if (!task.isComplete())
                {
                    throw task.getException();
                }
                return reference.getDownloadUrl();
            }
        }).addOnCompleteListener(new OnCompleteListener<Uri>() {
            @Override
            public void onComplete(@NonNull Task<Uri> task) {
                if (task.isSuccessful())
                {
                    Uri downloadUri = task.getResult();
                    myUrl = downloadUri.toString();

                    DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Categories")
                            .child(randomKey);

                    HashMap<String, Object> hashMap = new HashMap<>();
                    hashMap.put("categoryId", randomKey);
                    hashMap.put("categoryImage", myUrl);
                    hashMap.put("categoryName", editText.getText().toString());

                    databaseReference.setValue(hashMap);

                    save.setVisibility(View.VISIBLE);
                    startActivity(new Intent(AddCategoryActivity.this, CategoriesActivity.class));
                }
                else
                {
                    save.setVisibility(View.VISIBLE);
                    Toast.makeText(AddCategoryActivity.this, "Failed!", Toast.LENGTH_SHORT).show();
                }
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                save.setVisibility(View.VISIBLE);
                Toast.makeText(AddCategoryActivity.this, "" + e.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }
    else
    {
        save.setVisibility(View.VISIBLE);
        Toast.makeText(this, "No Image Selected", Toast.LENGTH_SHORT).show();
    }
}
英文:

I am sharing the code from my project:

Assign this globally:

StorageTask uploadTask;
String myUrl = &quot;&quot;;

and this is code:

private void uploadImage()
{
    if (imageUri != null)
    {
        final StorageReference reference = storageReference.child(System.currentTimeMillis()+&quot;.&quot;+getExtension(imageUri));
        uploadTask = reference.putFile(imageUri);
        uploadTask.continueWithTask(new Continuation() {
            @Override
            public Object then(@NonNull Task task) throws Exception {
                if (!task.isComplete())
                {
                    throw task.getException();
                }
                return reference.getDownloadUrl();
            }
        }).addOnCompleteListener(new OnCompleteListener&lt;Uri&gt;() {
            @Override
            public void onComplete(@NonNull Task&lt;Uri&gt; task) {
                if (task.isSuccessful())
                {
                    Uri downloadUri = task.getResult();
                    myUrl = downloadUri.toString();

                    DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference(&quot;Categories&quot;)
                            .child(randomKey);

                    HashMap&lt;String, Object&gt; hashMap = new HashMap&lt;&gt;();
                    hashMap.put(&quot;categoryId&quot;, randomKey);
                    hashMap.put(&quot;categoryImage&quot;, myUrl);
                    hashMap.put(&quot;categoryName&quot;, editText.getText().toString());

                    databaseReference.setValue(hashMap);

                    save.setVisibility(View.VISIBLE);
                    startActivity(new Intent(AddCategoryActivity.this, CategoriesActivity.class));
                }
                else
                {
                    save.setVisibility(View.VISIBLE);
                    Toast.makeText(AddCategoryActivity.this, &quot;Failed!&quot;, Toast.LENGTH_SHORT).show();
                }
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                save.setVisibility(View.VISIBLE);
                Toast.makeText(AddCategoryActivity.this, &quot;&quot;+e.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }
    else
    {
        save.setVisibility(View.VISIBLE);
        Toast.makeText(this, &quot;No Image Selected&quot;, Toast.LENGTH_SHORT).show();
    }
}

huangapple
  • 本文由 发表于 2020年7月25日 00:46:01
  • 转载请务必保留本文链接:https://java.coder-hub.com/63077974.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定