How to create an application that allows you to upload / modify a profile picture?

I searched high and low to find an example of how to implement profile image changes in my application. I want people to be able to add / modify their profile picture using Parse.com (similar to all social networking apps today).

For example: Twitter, Facebook, Instagram, etc., all of them allow you to upload or download a profile image, and this image is saved and can be viewed later.

I was not lucky to find any material that describes how to do this, and nothing else understands what I'm trying to achieve here:

The image downloaded from Parse remains on the screen even after exiting and reopening the application

Until now, in my application, the user could take a picture with the intention of the camera or upload an image from the gallery, and this image will be displayed in the image view perfectly.

The problem is this: when I exit and reopen the application, the image inside the image image is no longer displayed (it disappeared).

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); } } 
+6
source share
1 answer

First of all, I have to say that this is a very well-formulated question, and I would be glad that every guy with a small reputation asks such good-formulated questions.

The problem you are facing is mainly related to the Android Activity life cycle. I think the problem is really trivial: I do not see in your onCreate() activity the place where you are extracting the image from Parse: your load method is only called in onClickListener .

So instead of having it here, I would extract it to the private method, 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 a rough idea, I would be surprised if it compiles).

And then you call this method at the end of onCreate() ( onStart can work too, but I would prefer onCreate() ). Of course, you can call this method also from where it used to be (this actually happens if you literally extract the Right-Click > Refractor > Extract Method method)

Btw, itโ€™s very good that you use Picasso , but it would be better to initialize it using the Context 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 make sure that the image is uploaded and requested from the User table in Parse, this ensures that each user sees his own image (the currently registered image of the user), and not every other user who uploads the next image.

Hope this helps!

+2
source

All Articles