【问题标题】:Capturing Image from Camera and Upload to Firebase从相机捕获图像并上传到 Firebase
【发布时间】:2016-12-29 09:03:45
【问题描述】:

我正在开发一个简单的博客应用程序,该应用程序允许用户将照片从手机图库和描述上传到 Firebase 服务器。我正在尝试修改我当前的项目以允许用户从相机捕获照片并将其上传到 firebase 服务器。

目前,我可以将我捕获的图像显示到 imagebutton 中,但是我无法将我的图像发布到 firebase 服务器(“提交帖子”按钮对我的 onclick 功能没有反应)。

我怀疑我的 startPosting() 函数中存在一些错误,或者我没有正确编码图像?请帮忙。

package simpleblog2.emily.example.com.simpleblog2;

import android.app.ProgressDialog;
import android.content.ContentProvider;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.Image;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;

import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import com.squareup.picasso.Picasso;

import com.theartofdev.edmodo.cropper.CropImage;

import java.io.File;


public class PostActivity extends AppCompatActivity {

    private ImageButton mSelectImage;
    private EditText mPostTitle;
    private EditText mPostDesc;
    private Button mSubmitBtn;
    private ProgressDialog mProgress;
    private DatabaseReference mDatabase;

    private Uri mImageUri = null;

    private static final int GALLERY_REQUEST = 1;

    private static final int CAMERA_REQUEST_CODE = 1;

    private StorageReference mStorage;

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

        mStorage = FirebaseStorage.getInstance().getReference();
        mDatabase = FirebaseDatabase.getInstance().getReference().child("Blog");

        mSelectImage = (ImageButton) findViewById(R.id.imageSelect);
        mPostTitle = (EditText) findViewById(R.id.titleField);
        mPostDesc = (EditText) findViewById(R.id.descField);
        mSubmitBtn = (Button) findViewById(R.id.submitBtn);

        mProgress = new ProgressDialog(this);

        mSelectImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Intent intent1 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(intent1, CAMERA_REQUEST_CODE);
                intent1.setType("image/*");

                /*
                Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
                galleryIntent.setType("image/*");
                startActivityForResult(galleryIntent, GALLERY_REQUEST);
                */
            }
        });

        mSubmitBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startPosting();
            }
        });
    }

    private void startPosting() {

        mProgress.setMessage("Posting to blog...");


        final String title_val = mPostTitle.getText().toString().trim();
        final String desc_val = mPostDesc.getText().toString().trim();
        if (!TextUtils.isEmpty(title_val) && !TextUtils.isEmpty(desc_val) && mImageUri != null) {

            mProgress.show();
            StorageReference filepath = mStorage.child("Blog_Images").child(mImageUri.getLastPathSegment());

            filepath.putFile(mImageUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                    Uri downloadUrl = taskSnapshot.getDownloadUrl();

                    DatabaseReference newPost = mDatabase.push();
                    newPost.child("title").setValue(title_val);
                    newPost.child("desc").setValue(desc_val);
                    newPost.child("image").setValue(downloadUrl.toString());


                    mProgress.dismiss();
                    startActivity(new Intent(PostActivity.this, MainActivity.class));
                }
            });
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);




        // if(requestCode == GALLERY_REQUEST && resultCode == RESULT_OK){
        if (requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK) {

      /*   mImageUri = data.getData();
            mSelectImage.setImageURI(mImageUri);

            CropImage.activity(mImageUri)
                    .setGuidelines(CropImageView.Guidelines.ON)

                    .start(this);

*/

            Bitmap mImageUri = (Bitmap) data.getExtras().get("data");
            mSelectImage.setImageBitmap(mImageUri);
       }


        if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
            CropImage.ActivityResult result = CropImage.getActivityResult(data);
            if (resultCode == RESULT_OK) {
                Uri resultUri = result.getUri();
                mSelectImage.setImageURI(resultUri);
            } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) {
                Exception error = result.getError();
            }
        }


    }



}

【问题讨论】:

  • @DaminiMehra 你的答案是一个新函数,所以这个函数是替换我的 startPosting() 函数?我的代码做错了什么?

标签: android firebase android-camera firebase-storage


【解决方案1】:

我找到了我的问题的解决方案,我意识到我可以使用 data.getData() 函数而不是使用 Bitmap 函数来获取我捕获的数据:

 mImageUri = data.getData();
            mSelectImage.setImageURI(mImageUri);

另外,以前我没有意识到我的“裁剪”功能无法工作,因为我缺少:

mImageUri = resultUri;

我意识到有一个问题,如果我没有裁剪我捕获的图像,fire-base 无法处理高分辨率(或存储大小?它会加载非常慢/图像没有出现),这个可以通过“裁剪”功能解决。

最终代码如下: 感谢大家的帮助。

package simpleblog2.emily.example.com.simpleblog2;

import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.Image;
import android.net.Uri;

import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;


import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.storage.FirebaseStorage;

import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;


import com.theartofdev.edmodo.cropper.CropImage;
import com.theartofdev.edmodo.cropper.CropImageView;


public class PostActivity extends AppCompatActivity {

    private ImageButton mSelectImage;
    private EditText mPostTitle;
    private EditText mPostDesc;
    private Button mSubmitBtn;
    private ProgressDialog mProgress;
    private DatabaseReference mDatabase;

    private Uri mImageUri = null;

    private static final  int GALLERY_REQUEST =1;

    private static final int CAMERA_REQUEST_CODE=1;

    private StorageReference mStorage;

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

        mStorage = FirebaseStorage.getInstance().getReference();
        mDatabase = FirebaseDatabase.getInstance().getReference().child("Blog");

        mSelectImage = (ImageButton) findViewById(R.id.imageSelect);
        mPostTitle = (EditText)  findViewById(R.id.titleField);
        mPostDesc = (EditText) findViewById(R.id.descField);
        mSubmitBtn = (Button) findViewById(R.id.submitBtn);

        mProgress = new ProgressDialog(this);

        mSelectImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

                if (intent.resolveActivity(getPackageManager()) != null) {
                    startActivityForResult(intent, CAMERA_REQUEST_CODE);
                }
                //startActivityForResult(intent,CAMERA_REQUEST_CODE);


/*
                Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
                galleryIntent.setType("image/*");
                startActivityForResult(galleryIntent, GALLERY_REQUEST);

                */

            }
        });

        mSubmitBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startPosting();
            }
        });
    }



    private void startPosting(){

        mProgress.setMessage("Posting to blog...");


        final String title_val = mPostTitle.getText().toString().trim();
        final String desc_val = mPostDesc.getText().toString().trim();
        if(!TextUtils.isEmpty(title_val)&&!TextUtils.isEmpty(desc_val) && mImageUri != null){

            mProgress.show();
            StorageReference filepath = mStorage.child("Blog_Images").child(mImageUri.getLastPathSegment());

            filepath.putFile(mImageUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                    Uri downloadUrl =taskSnapshot.getDownloadUrl();

                    DatabaseReference newPost = mDatabase.push();
                    newPost.child("title").setValue(title_val);
                    newPost.child("desc").setValue(desc_val);
                    newPost.child("image").setValue(downloadUrl.toString());


                    mProgress.dismiss();
                    startActivity(new Intent(PostActivity.this,MainActivity.class));
                }
            });
        }
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
      // if(requestCode == GALLERY_REQUEST && resultCode == RESULT_OK){
       if(requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK){




        mImageUri = data.getData();
            mSelectImage.setImageURI(mImageUri);

            CropImage.activity(mImageUri)
                    .setGuidelines(CropImageView.Guidelines.ON)
                    .setAspectRatio(1,1)
                    .start(this);




        /* Bitmap mImageUri1 = (Bitmap) data.getExtras().get("data");
         mSelectImage.setImageBitmap(mImageUri1);

          Toast.makeText(this, "Image saved to:\n" +
                  data.getExtras().get("data"), Toast.LENGTH_LONG).show();


*/



        }

        if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
            CropImage.ActivityResult result = CropImage.getActivityResult(data);
            if (resultCode == RESULT_OK) {
                Uri resultUri = result.getUri();

                mSelectImage.setImageURI(resultUri);
                mImageUri = resultUri;

            } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) {
                Exception error = result.getError();
            }
        }


    }




}

【讨论】:

  • 我在 getdownloadurl() 中遇到错误我该如何解决它
【解决方案2】:

之前是 if auth != null 但我将其更改为 if true 因此 if 将始终评估为 true。

  private void uploadFile() {
    //if there is a file to upload
    if (filePath != null) {
        //displaying a progress dialog while upload is going on
        final ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setTitle("Uploading");
        progressDialog.show();

        StorageReference riversRef = storageReference.child("Blog_Images.jpg");
        riversRef.putFile(filePath)
                .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                    @Override
                    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                        //if the upload is successfull
                        //and displaying a success toast
                        Toast.makeText(getApplicationContext(), "File Uploaded ", Toast.LENGTH_LONG).show();
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception exception) {
                        //if the upload is not successfull
                        //hiding the progress dialog
                        progressDialog.dismiss();

                        //and displaying error message
                        Toast.makeText(getApplicationContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
                    }
                })
                .addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
                    @Override
                    public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
                        //calculating progress percentage
                        double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();

                        //displaying percentage in progress dialog
                        progressDialog.setMessage("Uploaded " + ((int) progress) + "%...");
                    }
                });
    }
    //if there is not any file
    else {
        //you can display an error toast
    }
}

【讨论】:

    【解决方案3】:

    您的类字段mImageUri 从未初始化。您将接收到的位图放在本地字段中,名称与类字段相同。

    Bitmap mImageUri = (Bitmap) data.getExtras().get("data");
    mSelectImage.setImageBitmap(mImageUri);
    

    因此,条件永远不会为真。

    if (!TextUtils.isEmpty(title_val) && !TextUtils.isEmpty(desc_val) && mImageUri != null) 
    

    【讨论】:

    • 我初始化,使用私有 Uri mImageUri = null;但它仍然给我同样的错误
    • 没错,你用null初始化它,然后检查它是否为null。您永远不会覆盖 null 值,因此条件 mImageUri !=null 永远不会为真。
    【解决方案4】:

       if (requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK) {
    
          /*   mImageUri = data.getData();
                mSelectImage.setImageURI(mImageUri);
    
                CropImage.activity(mImageUri)
                        .setGuidelines(CropImageView.Guidelines.ON)
    
                        .start(this);
    
    */
    
                Bitmap mImageUri = (Bitmap) data.getExtras().get("data");
                mSelectImage.setImageBitmap(mImageUri);
           }

    您的URI 有可能是null。我想,这就是问题所在。 除非你在别的地方做?

    图像可能已加载,因为 requestCode = CAMERA_REQUEST_CODE 但不是 CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE

    我将在我用来执行您要求的操作的代码下方发布,但首先您需要了解的几件事。 从 android 版本 7 开始,使用 Uri.parseFromFile(file) 返回错误,因为谷歌想要限制您的访问。从现在开始,如果你想获取文件 uri,你应该使用FileProvider

    1. 在清单中声明权限和 FileProvider:

           
    //File provider declaration in manifest.
            <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.hadas.yotam.manchworkers.provider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths"/>
            </provider>

    //in new xml file define the location you need permmision to, the code below give you permmision for any external file.
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path name="external_files" path="."/>
    </paths>

    所以现在上传时,如果 onActivityResault 成功,请使用全局 Uri 变量,代码如下:

    if(Build.VERSION.SDK_INT>=24) {
                                String file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)+"/" + Calendar.getInstance().getTimeInMillis() + ".jpg";
                                File file1 = new File(file);
                                photoURI = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", file1);
                                intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                            }

    然后在你的 onActivityResult 中检查你的 photoURI 是否 = null,如果它是真的(它的 null) 使用 photoURI = data.getData();

    //if phone android version greater or equal to Marshmelo                    
    
    if(Build.VERSION.SDK_INT>Build.VERSION_CODES.M){
    
    //check if have permmission to write to external + permmision to camera
    
                        if(ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED &&
                                ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED){
    
    //if its have permission then new intent to capture image
    
                            intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    
    //if android version >= 24 (Android Nugget)
    
                            if(Build.VERSION.SDK_INT>=24) {
    
    //create new String to pictures directory and set the file name to current_time.jpg
                                String file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)+"/" + Calendar.getInstance().getTimeInMillis() + ".jpg";
                                File file1 = new File(file);
    
    //set GLOBAL variable Uri from the file using FileProvider
    
                                photoURI = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", file1);
    
    //add the file location the intent (the picture will be save to this file)
    
                                intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                            }
                                tagIntent = CAPTURE_RESAULT;
    //else - dont have permission, request for permission
                        }else{
                            requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.CAMERA},CAPTURE_RESAULT);
                        }
    else - 
                    }else{
    // same thing only without FileProvider (FileProvider only required since Nugget)
    
                            intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                            String file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)+"/" + Calendar.getInstance().getTimeInMillis() + ".jpg";
                            File file1 = new File(file);
                            photoURI = Uri.fromFile(file1);
                            intent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI);
                        tagIntent = CAPTURE_RESAULT;
                    }
    
    //if phone can handle the intent, start the intent for resault.
    
                    if(intent.resolveActivity(getPackageManager())!=null) {
                startActivityForResult(intent,tagIntent);
                    }

    【讨论】:

    • 是的,我将它设置为私有 Uri mImageUri = null;这是我错误的原因吗?如果是这样,我应该怎么改变它?
    • 我做了一些你想要实现的事情,当我回到家时,我会上传代码的相关部分。
    • 一般情况下需要获取文件路径,但是从数据中获取url可能会返回null(依赖于android版本)。如果您使用版本 6 或更低版本,则可以使用:mImageUri = data.getData();如果您想确保获得 Uri,我会检查手机是否运行 android 6 或更高版本,以及是否确实为捕获意图添加了额外的文件位置并从文件中获取 uri。
    • 我编辑了我的答案,希望对您有所帮助。问题是,在低于版本 SDK 24 的手机上,您可以在 onActivityResault 中使用 mImageUri = data.getData() 但在上面它只返回一个缩略图而不是整个文件(不知道为什么)所以你告诉系统在哪里保存捕获图片,然后使用文件 + FileProvider 获取 URI
    • 我没有得到必须放置外部路径的部分,我在哪里放置代码?我去网上搜索developer.android.com/training/camera/photobasics.html我也无法理解代码应该放在哪里。
    猜你喜欢
    • 2021-08-20
    • 2019-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多