How To Create An App That Allows For Profile Pictu

2019-03-27 20:39发布

问题:

I have been searching high and low to find an example of how to implement profile picture changes within my app. I want to allow persons to add/change their profile image using Parse.com (Similar to all social media apps today).

For example: Twitter, Facebook, Instagram and so on, they all allow you to take/upload a profile image and that image is saved and can be viewed later on.

I have had no luck finding any material that covers how to do such a thing and no else seems to be understanding what I'm trying to achieve here:

An Image Downloaded From Parse Stay On Screen Even After You Exit And Reopen App?

So far in my app the user can take a picture with the camera intent or upload an image from gallery and that image is displayed in an Image View perfectly.

The problem is: when I exit and re-open the app the image inside of the Image View is no longer displayed (it is gone).

How can I solve this problem?

MainActivity:

     public class MainActivity extends AppCompatActivity {

        public static final int TAKE_PIC_REQUEST_CODE = 0;
        public static final int CHOOSE_PIC_REQUEST_CODE = 1;
        public static final int MEDIA_TYPE_IMAGE = 2;

        private Uri mMediaUri;

        private TextView mChangeProfilePic;
        protected ImageView mPreviewImageView;
        private Button mSaveChangesBtn;
        public ImageView mProfilePic;


        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);


            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                            .setAction("Action", null).show();
                }
            });


            //Initialize variables
            mChangeProfilePic = (TextView) findViewById(R.id.changeProfileImageTxt);
            mPreviewImageView = (ImageView) findViewById(R.id.profileImage);
            mSaveChangesBtn = (Button) findViewById(R.id.saveProfileChangesBtn);
            mSaveChangesBtn.setEnabled(false);

            final Button mNextBtn = (Button) findViewById(R.id.NextBtn);
            mNextBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intentNext = new Intent(MainActivity.this, SecondActivity.class);
                    startActivity(intentNext);
                }
            });


            //Change profile image
            //set onlClick to TextView
            mChangeProfilePic.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(getApplicationContext(), "Change Pic Pressed", Toast.LENGTH_SHORT).show();

                    //show dialog
                    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                    builder.setTitle("Upload or Take a photo");
                    builder.setPositiveButton("Upload", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            //upload image
                            Intent choosePictureIntent = new Intent(Intent.ACTION_GET_CONTENT);
                            choosePictureIntent.setType("image/*");
                            startActivityForResult(choosePictureIntent, CHOOSE_PIC_REQUEST_CODE);

                            mSaveChangesBtn.setEnabled(true);

                        }
                    });
                    builder.setNegativeButton("Take Photo", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            //take photo
                            Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                            mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
                            if (mMediaUri == null) {
                                //display error
                                Toast.makeText(getApplicationContext(), "Sorry there was an error! Try again.", Toast.LENGTH_LONG).show();

                                mSaveChangesBtn.setEnabled(false);

                            } else {
                                takePicture.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
                                startActivityForResult(takePicture, TAKE_PIC_REQUEST_CODE);

                                mSaveChangesBtn.setEnabled(true);
                            }
                        }
                    });
                    AlertDialog dialog = builder.create();
                    dialog.show();
                }
            });//End change profile image onClick Listener


            //Save profile changes button
            //Also uploads content to parse and pulls it back same time
            mSaveChangesBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    //create parse object for image to upload
                    final ParseObject imageUpload = new ParseObject("ImageUploads");
                    try {
                        //convert image to bytes for upload.
                        byte[] fileBytes = FileHelper.getByteArrayFromFile(MainActivity.this, mMediaUri);
                        if (fileBytes == null) {
                            //there was an error
                            Toast.makeText(getApplicationContext(), "There was an error. Try again!", Toast.LENGTH_LONG).show();

                            mSaveChangesBtn.setEnabled(false);
                        } else {

                            fileBytes = FileHelper.reduceImageForUpload(fileBytes);
                            String fileName = FileHelper.getFileName(MainActivity.this, mMediaUri, "image");
                            final ParseFile file = new ParseFile(fileName, fileBytes);
                            imageUpload.saveEventually(new SaveCallback() {
                                @Override
                                public void done(ParseException e) {
                                    if (e == null) {

                                        imageUpload.put("imageContent", file);
                                        imageUpload.saveInBackground(new SaveCallback() {
                                                                         @Override
                                                                         public void done(ParseException e) {
                                                                             Toast.makeText(getApplicationContext(), "Success Uploading iMage!", Toast.LENGTH_LONG).show();

                                                                             //Retrieve the recently saved image from Parse
                                                                             queryParseProfileImages(imageUpload);

                                                                             mSaveChangesBtn.setEnabled(false);
                                                                         }
                                                                     }

                                        );
                                    } else {
                                        //there was an error
                                        Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();

                                        mSaveChangesBtn.setEnabled(false);
                                    }
                                }
                            });

                        }

                    } catch (Exception e1) {
                        Toast.makeText(getApplicationContext(), e1.getMessage(), Toast.LENGTH_LONG).show();
                    }
                }//End onClick(View v)

            });//End onClick Listener


//This method queries for the most recent picture taken
ParseQuery<ParseObject> imagesQuery = new ParseQuery<>("ImageUploads");
            imagesQuery.orderByDescending("createdAt");
            imagesQuery.findInBackground(new FindCallback<ParseObject>() {
                @Override
                public void done(List<ParseObject> images, ParseException e) {
                    if(e == null){

                        //for (int i = 0; i < images.size(); i++) {

                            final String imgUrl = images.get(0).getParseFile("imageContent").getUrl();


                            mProfilePic = (ImageView) findViewById(R.id.profileImage);
                            Picasso.with(MainActivity.this).load(imgUrl).into(mProfilePic);

                        //}
                        //images.pinInBackground();

                        //profileImageId = profImgObj.getObjectId();
                        //Log.d(TAG, "The object id is: " + profileImageId);
                    }else{
                        Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
                    }
                }
            });



        }//End onCreate


        //Method containing ParseQuery to download/pull back the image that was uploaded to Parse
        //Inside the Image View
        private void queryParseProfileImages(final ParseObject imageUploadPassed) {

            ParseFile userImageRetrievedObj = (ParseFile) imageUploadPassed.get("imageContent");
            userImageRetrievedObj.getDataInBackground(new GetDataCallback() {
                public void done(byte[] data, ParseException e) {
                    if (e == null) {


                        final String imgUrl = imageUploadPassed.getParseFile("imageContent").getUrl();


                        mProfilePic = (ImageView) findViewById(R.id.profileImage);
                        Picasso.with(MainActivity.this).load(imgUrl).into(mProfilePic);

                        imageUploadPassed.pinInBackground();


                    } else {
                        // something went wrong
                    }
                }
            });


        }


        //inner helper method
        private Uri getOutputMediaFileUri(int mediaTypeImage) {

            if (isExternalStorageAvailable()) {
                //get the URI
                //get external storage dir
                File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "UPLOADIMAGES");
                //create subdirectore if it does not exist
                if (!mediaStorageDir.exists()) {
                    //create dir
                    if (!mediaStorageDir.mkdirs()) {

                        return null;
                    }
                }
                //create a file name
                //create file
                File mediaFile = null;
                Date now = new Date();
                String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(now);

                String path = mediaStorageDir.getPath() + File.separator;
                if (mediaTypeImage == MEDIA_TYPE_IMAGE) {
                    mediaFile = new File(path + "IMG_" + timestamp + ".jpg");
                }
                //return file uri
                Log.d("UPLOADIMAGE", "FILE: " + Uri.fromFile(mediaFile));

                return Uri.fromFile(mediaFile);
            } else {

                return null;
            }

        }

        //check if external storage is mounted. helper method
        private boolean isExternalStorageAvailable() {
            String state = Environment.getExternalStorageState();
            if (state.equals(Environment.MEDIA_MOUNTED)) {
                return true;
            } else {
                return false;
            }
        }

        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode == RESULT_OK) {
                if (requestCode == CHOOSE_PIC_REQUEST_CODE) {
                    if (data == null) {
                        Toast.makeText(getApplicationContext(), "Image cannot be null!", Toast.LENGTH_LONG).show();
                    } else {
                        mMediaUri = data.getData();
                        //set previews
                        mPreviewImageView.setImageURI(mMediaUri);

                        //Bundle extras = data.getExtras();

                        //Log.e("URI", mMediaUri.toString());

                        //Bitmap bmp = (Bitmap) extras.get("data");


                    }
                } else {

                    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                    mediaScanIntent.setData(mMediaUri);
                    sendBroadcast(mediaScanIntent);
                    //set previews

                    mPreviewImageView.setImageURI(mMediaUri);

                }

            } else if (resultCode != RESULT_CANCELED) {
                Toast.makeText(getApplicationContext(), "Cancelled!", Toast.LENGTH_LONG).show();
            }
        }


        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.menu_main, menu);
            return true;
        }


        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();

            //noinspection SimplifiableIfStatement
            if (id == R.id.action_settings) {
                return true;
            }

            return super.onOptionsItemSelected(item);
        }
    }

回答1:

First, I have to say that this a really well formulated question and I would be happy that every guy with few reputation asks so good formulated questions.

The problem you encounter is basically an issue with the Android Activity lifecycle. I guess, the problem is really trivial: I see nowhere in your Activity onCreate() a place where you retrieve the image from Parse: your download method is only called in a onClickListener.

So instead of having it here, I would extract it to a private method, kind of something like this:

Edit:

   private void queryImagesFromParse(){
        ParseQuery<ParseObject> imagesQuery = new ParseQuery<>("User");
        imagesQuery.findInBackground(new FindCallback<ParseObject>() {
            @Override
            public void done(List<ParseObject> imagesItems, ParseException e) {
                if(e == null){

                    ParseUser userCurrentOfParse = ParseUser.getCurrentUser();
                    if(userCurrentOfParse != null) {
                        //final String imgUrl = imageUploadPassed.getParseFile("imageContent").getUrl();
                        final String imgUrl = userCurrentOfParse.getParseFile("userProfilePics").getUrl();


                        mHomeProfilePic = (ImageView) findViewById(R.id.userHomeProfilePicImageView);
                        Picasso.with(HomeActivity.this).load(imgUrl).into(mHomeProfilePic);

                        //imageUploadPassed.pinInBackground();

                       // profileImageId = imageUploadPassed.getObjectId();
                        //Log.d(TAG, "The object id is: " + profileImageId);
                    }

                }else{
                    Toast.makeText(HomeActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
                }
            }
        });
    }

(The code above is just to give an rough idea, I would be surprised if it compiles).

And then, you call this method at the end of the onCreate() (onStart could work as well, but I'd prefer onCreate()). Of course, you can call this method also from the place where it was before (that is actually what happens if you literally extract the method Right-Click > Refractor > Extract Method)

Btw, very good that you use Picasso but it could be better to initialise it with the Context of your Activity so Picasso.with(MainActivity.this).load(imgUrl).into(mProfilePic); instead of Picasso.with(getApplicationContext()).load(imgUrl).into(mProfilePic); (should be 1 ns faster!)

Edit: Also be sure that the image is being upload and queried from the User table on Parse this will ensure that each user will see their own image(currently logged in user's image) and not that of every other user that uploads the next image.

Hope it helps!