简体   繁体   English

上传图片时出现Firebase NullPointerException

[英]Firebase NullPointerException at image upload

In my firebase application and I have an issue unable to solve. 在我的Firebase应用程序中,我有一个无法解决的问题。

In my AccountFragment Im trying to upload an user profile image - After selecting the image, the application craches. 在我的AccountFragment中,我试图上传用户个人资料图片-选择图片后,应用程序崩溃了。 Please help me fix this 请帮我解决这个问题

I have been on this for days now, Im really lost here. 我已经参加了好几天了,我真的在这里迷路了。

The application only crashes when I try to upload an image, When I try to update name, phone number, or email - All is working fine 仅当我尝试上传图像,当我尝试更新名称,电话号码或电子邮件时,应用程序才会崩溃-一切正常

package com.company.walt.fragments;

public class AccountFragment extends BaseFragment implements
        ChangePhotoDialog.OnPhotoReceivedListener {

    // Statics
    private static final String TAG = "AccountFragment";

    private static final int REQUEST_CODE = 1234;
    private static final double MB_THRESHHOLD = 5.0;
    private static final double MB = 1000000.0;

    // Widgets
    private ImageView mProfileImage;
    private EditText mName;
    private EditText mEmail;
    private EditText mPhone;
    private EditText mConfirm;
    private Button mUpdateBtn;

    // Vars
    private boolean mStoragePermissions;
    private Uri mSelectedImageUri;
    private Bitmap mSelectedImageBitmap;
    private byte[] mBytes;
    private double progress;

    public AccountFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_account, container, false);

        mProfileImage = (ImageView)view.findViewById(R.id.user_img);
        mName = (EditText) view.findViewById(R.id.input_name);
        mEmail = (EditText) view.findViewById(R.id.input_email);
        mPhone = (EditText) view.findViewById(R.id.input_phone);
        mConfirm = (EditText) view.findViewById(R.id.input_confirm);
        mUpdateBtn = (Button) view.findViewById(R.id.btn_update);

        setupFirebaseAuth();

        updateInformation();

        hideSoftKeyboard();

        return view;
    }

    private void updateInformation(){

        mProfileImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                if(mStoragePermissions){
                    ChangePhotoDialog dialog = new ChangePhotoDialog();
                    dialog.show(getChildFragmentManager(), "ChangePhotoDialog");

                }else{
                    verifyStoragePermissions();
                }

            }
        });

        mUpdateBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Log.d(TAG, "onClick: Attempting to save settings");

                DatabaseReference reference = FirebaseDatabase.getInstance().getReference();

                // If user only wants to update name
                if (!isEmpty(mName.getText().toString())) {

                    reference.child(getString(R.string.dbnode_users))
                            .child(FirebaseAuth.getInstance().getCurrentUser().getUid())
                            .child(getString(R.string.field_name))
                            .setValue(mName.getText().toString());

                    Toast.makeText(getActivity(), "Your name have been updated", Toast.LENGTH_SHORT).show();

                }

                // If user only wants to update phone
                if (!isEmpty(mPhone.getText().toString())) {

                    reference.child(getString(R.string.dbnode_users))
                            .child(FirebaseAuth.getInstance().getCurrentUser().getUid())
                            .child(getString(R.string.field_phone))
                            .setValue(mPhone.getText().toString());

                    Toast.makeText(getActivity(), "Your phone have been updated", Toast.LENGTH_SHORT).show();

                }

                // If user only wants to update email
                if (!isEmpty(mEmail.getText().toString())
                        && !isEmpty(mConfirm.getText().toString())) {

                    updateUserEmailOnly();

                }
                if (!isEmpty(mEmail.getText().toString())
                        && isEmpty(mConfirm.getText().toString())) {
                    Toast.makeText(getActivity(), "You must enter password to change email", Toast.LENGTH_SHORT).show();
                }
                else if (isEmpty(mEmail.getText().toString())
                        && !isEmpty(mConfirm.getText().toString())) {

                    Toast.makeText(getActivity(), "You only entered password, nothing will happen", Toast.LENGTH_SHORT).show();

                }


                /*
                ------ Upload the New Photo -----
                 */
                if(mSelectedImageUri != null){
                    uploadNewPhoto(mSelectedImageUri);
                }else if(mSelectedImageBitmap  != null){
                    uploadNewPhoto(mSelectedImageBitmap);
                }


            }

        });

    }

    /**
     * Uploads a new profile photo to Firebase Storage using a @param ***imageUri***
     * @param imageUri
     */
    public void uploadNewPhoto(Uri imageUri){
        /*
            upload a new profile photo to firebase storage
         */
        Log.d(TAG, "uploadNewPhoto: uploading new profile photo to firebase storage.");

        //Only accept image sizes that are compressed to under 5MB. If thats not possible
        //then do not allow image to be uploaded
        BackgroundImageResize resize = new BackgroundImageResize(null);
        resize.execute(imageUri);
    }

    /**
     * Uploads a new profile photo to Firebase Storage using a @param ***imageBitmap***
     * @param imageBitmap
     */
    public void uploadNewPhoto(Bitmap imageBitmap){
        /*
            upload a new profile photo to firebase storage
         */
        Log.d(TAG, "uploadNewPhoto: uploading new profile photo to firebase storage.");

        //Only accept image sizes that are compressed to under 5MB. If thats not possible
        //then do not allow image to be uploaded
        BackgroundImageResize resize = new BackgroundImageResize(imageBitmap);
        Uri uri = null;
        resize.execute(uri);
    }

    /**
     * 1) doinBackground takes an imageUri and returns the byte array after compression
     * 2) onPostExecute will print the % compression to the log once finished
     */
    public class BackgroundImageResize extends AsyncTask<Uri, Integer, byte[]> {

        Bitmap mBitmap;
        public BackgroundImageResize(Bitmap bm) {
            if(bm != null){
                mBitmap = bm;
            }
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            showProgress();
            Toast.makeText(getActivity(), "compressing image", Toast.LENGTH_SHORT).show();
        }

        @Override
        protected byte[] doInBackground(Uri... params ) {
            Log.d(TAG, "doInBackground: started.");

            if(mBitmap == null){

                try {
                    mBitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), params[0]);
                    Log.d(TAG, "doInBackground: bitmap size: megabytes: " + mBitmap.getByteCount()/MB + " MB");
                } catch (IOException e) {
                    Log.e(TAG, "doInBackground: IOException: ", e.getCause());
                }
            }

            byte[] bytes = null;
            for (int i = 1; i < 11; i++){
                if(i == 10){
                    Toast.makeText(getActivity(), "That image is too large.", Toast.LENGTH_SHORT).show();
                    break;
                }
                bytes = getBytesFromBitmap(mBitmap,100/i);
                Log.d(TAG, "doInBackground: megabytes: (" + (11-i) + "0%) "  + bytes.length/MB + " MB");
                if(bytes.length/MB  < MB_THRESHHOLD){
                    return bytes;
                }
            }
            return bytes;
        }


        @Override
        protected void onPostExecute(byte[] bytes) {
            super.onPostExecute(bytes);
            hideProgress();
            mBytes = bytes;
            //execute the upload
            executeUploadTask();
        }
    }

    // convert from bitmap to byte array
    public static byte[] getBytesFromBitmap(Bitmap bitmap, int quality) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream);
        return stream.toByteArray();
    }

    private void executeUploadTask(){
        showProgress();
        FilePaths filePaths = new FilePaths();

        //specify where the photo will be stored
        final StorageReference storageReference = FirebaseStorage.getInstance().getReference()
                .child(filePaths.FIREBASE_USER_IMAGE_STORAGE + "/" + FirebaseAuth.getInstance().getCurrentUser().getUid()
                        + "/profile_image"); //just replace the old image with the new one

        if(mBytes.length/MB < MB_THRESHHOLD) {

            // Create file metadata including the content type
            StorageMetadata metadata = new StorageMetadata.Builder()
                    .setContentType("image/jpg")
                    .setContentLanguage("en") //see nodes below
                    /*
                    Make sure to use proper language code ("English" will cause a crash)
                    I actually submitted this as a bug to the Firebase github page so it might be
                    fixed by the time you watch this video. You can check it out at https://github.com/firebase/quickstart-unity/issues/116
                     */
                    .setCustomMetadata("Mitch's special meta data", "JK nothing special here")
                    .setCustomMetadata("location", "Iceland")
                    .build();
            //if the image size is valid then we can submit to database
            UploadTask uploadTask = null;
            uploadTask = storageReference.putBytes(mBytes, metadata);
            //uploadTask = storageReference.putBytes(mBytes); //without metadata


            uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                    //Now insert the download url into the firebase database
                    Uri firebaseURL = taskSnapshot.getDownloadUrl();
                    Toast.makeText(getActivity(), "Upload Success", Toast.LENGTH_SHORT).show();
                    Log.d(TAG, "onSuccess: firebase download url : " + firebaseURL.toString());
                    FirebaseDatabase.getInstance().getReference()
                            .child(getString(R.string.dbnode_users))
                            .child(FirebaseAuth.getInstance().getCurrentUser().getUid())
                            .child(getString(R.string.field_profile_image))
                            .setValue(firebaseURL.toString());

                    hideProgress();
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception exception) {
                    Toast.makeText(getActivity(), "could not upload photo", Toast.LENGTH_SHORT).show();

                    hideProgress();

                }
            }).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
                    double currentProgress = (100 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
                    if(currentProgress > (progress + 15)){
                        progress = (100 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
                        Log.d(TAG, "onProgress: Upload is " + progress + "% done");
                        Toast.makeText(getActivity(), progress + "%", Toast.LENGTH_SHORT).show();
                    }

                }
            })
            ;
        }else{
            Toast.makeText(getActivity(), "Image is too Large", Toast.LENGTH_SHORT).show();
        }

    }

    /**
     * Generalized method for asking permission. Can pass any array of permissions
     */
    public void verifyStoragePermissions(){
        Log.d(TAG, "verifyPermissions: asking user for permissions.");
        String[] permissions = {
                android.Manifest.permission.READ_EXTERNAL_STORAGE,
                android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.CAMERA};

        if (ContextCompat.checkSelfPermission(this.getActivity(),
                permissions[0] ) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(this.getActivity(),
                permissions[1] ) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(this.getActivity(),
                permissions[2] ) == PackageManager.PERMISSION_GRANTED) {

            mStoragePermissions = true;

        }
        else {

            ActivityCompat.requestPermissions(getActivity(), permissions, REQUEST_CODE);
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        Log.d(TAG, "onRequestPermissionsResult: requestCode: " + requestCode);
        switch(requestCode){
            case REQUEST_CODE:
                if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    Log.d(TAG, "onRequestPermissionsResult: User has allowed permission to access: " + permissions[0]);

                }
                break;
        }
    }

    @Override
    public void getImagePath(Uri imagePath) {
        if( !imagePath.toString().equals("")){
            mSelectedImageBitmap = null;
            mSelectedImageUri = imagePath;
            Log.d(TAG, "getImagePath: got the image uri: " + mSelectedImageUri);
            ImageLoader.getInstance().displayImage(imagePath.toString(), mProfileImage);
        }

    }

    @Override
    public void getImageBitmap(Bitmap bitmap) {
        if(bitmap != null){
            mSelectedImageUri = null;
            mSelectedImageBitmap = bitmap;
            Log.d(TAG, "getImageBitmap: got the image bitmap: " + mSelectedImageBitmap);
            mProfileImage.setImageBitmap(bitmap);
        }
    }

    /*
    * **********************************************************************************************
    * USER OPTION METHODS
    * */

    /**
     * Update Email Only
     */
    private void updateUserEmailOnly() {

        showProgress();

        AuthCredential credential = EmailAuthProvider
                .getCredential(FirebaseAuth.getInstance().getCurrentUser().getEmail(), mConfirm.getText().toString());

        FirebaseAuth.getInstance().getCurrentUser().reauthenticate(credential)
                .addOnCompleteListener(new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {

                        if (task.isSuccessful()) {

                            Log.d(TAG, "onComplete: reauthenticate success.");

                            ///////////////////now check to see if the email is not already present in the database
                            FirebaseAuth.getInstance().fetchProvidersForEmail(mEmail.getText().toString()).addOnCompleteListener(
                                    new OnCompleteListener<ProviderQueryResult>() {
                                        @Override
                                        public void onComplete(@NonNull Task<ProviderQueryResult> task) {

                                            if (task.isSuccessful()) {

                                                ///////// getProviders().size() will return size 1 if email ID is in use.
                                                Log.d(TAG, "onComplete: RESULT: " + task.getResult().getProviders().size());

                                                if (task.getResult().getProviders().size() == 1) {
                                                    Log.d(TAG, "onComplete: That email is already in use.");

                                                    hideProgress();
                                                    Toast.makeText(getActivity(), "That email is already in use", Toast.LENGTH_SHORT).show();
                                                } else {
                                                    Log.d(TAG, "onComplete: That email is available.");

                                                    /////////////////////add new email
                                                    FirebaseAuth.getInstance().getCurrentUser().updateEmail(mEmail.getText().toString())
                                                            .addOnCompleteListener(new OnCompleteListener<Void>() {
                                                                @Override
                                                                public void onComplete(@NonNull Task<Void> task) {
                                                                    if (task.isSuccessful()) {
                                                                        Log.d(TAG, "onComplete: User email address updated.");
                                                                        Toast.makeText(getActivity(), "Updated email", Toast.LENGTH_SHORT).show();
                                                                        sendVerificationEmail();
                                                                        FirebaseAuth.getInstance().signOut();
                                                                    } else {
                                                                        Log.d(TAG, "onComplete: Could not update email.");
                                                                        Toast.makeText(getActivity(), "unable to update email", Toast.LENGTH_SHORT).show();
                                                                    }

                                                                    hideProgress();
                                                                }
                                                            })
                                                            .addOnFailureListener(new OnFailureListener() {
                                                                @Override
                                                                public void onFailure(@NonNull Exception e) {
                                                                    hideProgress();
                                                                    Toast.makeText(getActivity(), "unable to update email", Toast.LENGTH_SHORT).show();
                                                                }
                                                            });
                                                }
                                            }

                                        }
                                    })
                                    .addOnFailureListener(new OnFailureListener() {
                                        @Override
                                        public void onFailure(@NonNull Exception e) {
                                            hideProgress();
                                            Toast.makeText(getActivity(), "“unable to update email”", Toast.LENGTH_SHORT).show();
                                        }
                                    });

                        } else {
                            Log.d(TAG, "onComplete: Incorrect Password");
                            Toast.makeText(getActivity(), "Incorrect Password", Toast.LENGTH_SHORT).show();
                            hideProgress();
                        }
                    }

                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        hideProgress();
                        Toast.makeText(getActivity(), "“unable to update email”", Toast.LENGTH_SHORT).show();
                    }
                });
    }

    /**
     * sends an email verification link to the user
     */
    public void sendVerificationEmail() {

        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();

        if (user != null) {
            user.sendEmailVerification()
                    .addOnCompleteListener(new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {
                            if (task.isSuccessful()) {
                                Toast.makeText(getActivity(), "Sent Verification Email", Toast.LENGTH_SHORT).show();
                            } else {
                                Toast.makeText(getActivity(), "Couldn't Verification Send Email", Toast.LENGTH_SHORT).show();
                            }
                        }
                    });
        }

    }

    /**
     * Return true if the @param is null
     * @param string
     * @return
     */
    private boolean isEmpty(String string) {
        return string.equals("");
    }

    /*
    * **********************************************************************************************
    * INHERITED METHODS
    * */

    /**
     * Display progressbar
     */
    protected void showProgress() {
        if (getActivity() instanceof IProgressDisplay) {
            ((IProgressDisplay) getActivity()).showProgress();
        }
    }

    /**
     * Hide progressbar
     */
    protected void hideProgress() {
        if (getActivity() instanceof IProgressDisplay) {
            ((IProgressDisplay) getActivity()).hideProgress();
        }
    }

    /**
     * Hide softKeyboard
     */
    protected void hideSoftKeyboard() {
        if (getActivity() instanceof ISoftKeyboard) {
            ((ISoftKeyboard) getActivity()).hideSoftKeyboard();
        }
    }

    /**
     * Firebase Auth
     */
    protected void setupFirebaseAuth() {
        if (getActivity() instanceof IFirebaseAuth) {
            ((IFirebaseAuth) getActivity()).setupFirebaseAuth();
        }
    }
}

This is the LogCat 这是LogCat

01-02 20:34:41.590 16223-16223/com.company.walt E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.company.walt, PID: 16223
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=73888, result=-1, data=Intent { dat=content://com.android.providers.media.documents/document/image:672 flg=0x1 }} to activity {com.company.walt/com.company.walt.activities.MainActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'void com.company.walt.Dialogs.ChangePhotoDialog$OnPhotoReceivedListener.getImagePath(android.net.Uri)' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:4528)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4571)
at android.app.ActivityThread.-wrap19(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1744)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6809)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void com.company.walt.Dialogs.ChangePhotoDialog$OnPhotoReceivedListener.getImagePath(android.net.Uri)' on a null object reference
at com.company.walt.Dialogs.ChangePhotoDialog.onActivityResult(ChangePhotoDialog.java:78)
at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:151)
at android.app.Activity.dispatchActivityResult(Activity.java:7267)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4524)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4571) 
at android.app.ActivityThread.-wrap19(Unknown Source:0) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1744) 
at android.os.Looper.loop(Looper.java:164) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 
01-02 20:34:41.591 468-468/? W/auditd: type=1400 "memtrack@1.0-se""mem""debugfs"

You are getting that error because you are calling a method on an uninitialized object and that's why you are getting a NullPointerException . 之所以得到该错误,是因为您要在未初始化的对象上调用方法,这就是为什么要获取NullPointerException的原因。 To solve this, you only need to initialize your variable on which you are calling getImagePath() method. 要解决此问题,只需初始化要在其上调用getImagePath()方法的变量。 Also make sure every time you are using an object to check for nullity . 另外,还要确保你每次使用一个对象来检查nullity

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM