Android how to set and retrieve data from Preference object - java

I am working on a preference fragment, one preference is to select an external image file as the app background.
I try to save the file path string to the correspond preference, so that I can load that path data from SharedPreferences when the app is launched.
My problem is when using Preference class instead of EditTextPreference, there is no setText() method to save the path value, and I cannot figure out how to store the data onto a Preference object and then retrieve through SharedPreferences.getString("key", "") in my activity.
If I use a EditTextPreference instead, indeed it works but I have to disable or customize the dialog component of EditTextPreference, since I need to start a new activity to pick a image when tapping this preference.
I notice in the official documentation they use Preference when using intent together. Is there any way to save data to a Preference object and then retrieve that data in an activity?
// In preference fragment
private Preference bgPref;
#Override
public void onActivityResult(
int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && data != null) {
Uri imageUri = data.getData();
final String path = getFilePath(requireContext(), imageUri);
if (path != null) {
bgPref.setText(path); // how to set a string value for a Preference?
Drawable d = Drawable.createFromPath(path);
if (containerView != null) {
containerView.setBackground(d);
}
}
} else {
Toast.makeText(requireContext(), "You haven't picked Image", Toast.LENGTH_LONG).show();
}
}
// In Main activity
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
String bgPath = sharedPrefs.getString("bgPath", "");
Drawable d = Drawable.createFromPath(bgPath);
if (!bgPath.isEmpty()) findViewById(R.id.nav_host_fragment).setBackground(d);
//...

You can edit this preference directly. In onActivityResult():
#Override
public void onActivityResult(
int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && data != null) {
Uri imageUri = data.getData();
final String path = getFilePath(requireContext(), imageUri);
if (path != null) {
// Save preference here
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString("bgPath", path);
editor.apply();
// Now recreate activity to refresh the UI
requireActivity().recreate();
// In onCreateView, you can use this preference to set background
}
} else {
Toast.makeText(requireContext(), "You haven't picked Image", Toast.LENGTH_LONG).show();
}
}
}

Related

Upload your own profile picture

When I start the application, I upload an image using Picasso to imageview. I'm trying to make the user upload their own image. If I take a picture or select it from the gallery, I can display it in an imageview. But I would like to use SharedPreferences to display the image the next time I load the application, which I unfortunately can't do.
Here is my code.
private void showImageOptionDialog(){
final String[] options = getResources().getStringArray(R.array.image_options);
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(R.string.alert_dialog_title)
.setItems(options, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case 0:
Intent cameraIntent = new Intent();
cameraIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, 11);
break;
case 1:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, 9);
break;
case 2:
SaveSharedPreference.setAvatar(context, "none");
recreate();
break;
}
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//Check if the intent was to pick image, was successful and an image was picked
if(requestCode == 9 && resultCode == RESULT_OK && data != null){
//Get selected image uri from phone gallery
Uri selectedImage = data.getData();
//Display selected photo in image view
//head_image.setImageURI(selectedImage);
assert selectedImage != null;
SaveSharedPreference.setAvatar(context, selectedImage.toString());
}
//Handle camera request
else if(requestCode == 11 && resultCode == RESULT_OK && data != null){
//We need a bitmap variable to store the photo
Bitmap bitmap = (Bitmap) Objects.requireNonNull(data.getExtras()).get("data");
//Display taken picture in image view
head_image.setImageBitmap(bitmap);
}
recreate();
}
Then I try to load using
Picasso.get()
.load(SaveSharedPreference.getAvatar(context))
.placeholder(R.mipmap.ic_launcher)
.transform(new CropCircleTransformation())
.into(head_image);
Thank you for your help
(application runs on Android 7.0+)
It's NOT a good idea to save a photo using SharedPreferences. Try caching it or use a local Database or File system to store and/or restore them

Need help on how to use onActivityResult() on Adapter Class?

I tried to return a phone number from a contact list on my adapter class, when i use super.onActivityResult(requestCode, resultCode, data); I got error.
btnContactGift.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_PICK,
ContactsContract.Contacts.CONTENT_URI);
// Show only contacts with phone numbers
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
// Start the Contacts activity
context.startActivityForResult(intent, PICK_CONTACT);
}
});
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case PICK_CONTACT :
if (resultCode == Activity.RESULT_OK) {
Uri contactData = data.getData();
String[] projection = {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Photo.PHOTO_THUMBNAIL_URI};
Cursor c = conR.query(contactData, projection, null, null, null);
c.moveToFirst();
int nameIdx =c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int phoneNumberIdx =c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int photoIdx = c.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO_THUMBNAIL_URI);
String name = c.getString(nameIdx);
String phoneNumber = c.getString(phoneNumberIdx);
String photo = c.getString(photoIdx);
if (name == null) {
name = "No Name";
}
String nwPhone = phoneNumber.replace("+251", "0");
edtPhoneGift.setText(nwPhone);
c.close();
// Now you have the phone number
}
break;
}
}
Can not resolve method onActivityResult(int, int, Intent)
onActivityResult() needs to be implemented on the activity or fragment on which you call startActivityForResult(). In your case, that would be whatever activity or fragment is identified by context (from context.startActivityForResult(intent, PICK_CONTACT)).
Just delete the call to super super.onActivityResult(requestCode, resultCode, data), you don't need that.
Also, you need to change the ContactsContract.CommonDataKinds.Photo.PHOTO_THUMBNAIL_URI in your projection to something else, you can get Photo.XXX fields from the Uri returned from a Phone Picker intent, only columns within Phone.XXX or implicitly joined to it, you can try using Contacts.PHOTO_ID instead.

Is there a "stock" chooser for image content providers?

For instance, when I want to attach an image to a text message in the stock Messages app, I get a familiar system dialog presenting the Camera, Gallery, and other image Content Providers.
I want to use this in my own app. I see plenty of libraries that allow the user to choose between Gallery and Camera, but I want all of the user's installed Image source to appear.
Is the system dialog from Messages (and other stock apps, such as Mail) really custom for those apps? Do we really need to build our own? Storage Access Framework does not appear to be the right solution since it bypasses the camera (or other image sources that I haven't thought of but may be present on a user's device).
I would suggest Intent.ACTION_PICK
private void selectFileFromGallery() {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), requestGallery);
}
It will open a dialog like this that contains all of users app that can be used as an image picker :
And then when user chosses image:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == requestGallery) {
onSelectFromGalleryResult(data);
}
}
#SuppressWarnings("deprecation")
private void onSelectFromGalleryResult(Intent data) {
Uri uri = data.getData();
if (!uri.toString().contains("file")) {
if (uri.toString().contains("external")) {//chosen from external storage
photoUri = Uri.parse("file://" + getRealPathFromURI(uri));
} else {
photoUri = Uri.parse("file://" + (Build.VERSION.SDK_INT <= 18
? getRealPathFromURI_API11to18(getActivity(), uri) :
getRealPathFromURI_API19(getActivity(), uri)));
}
}
#SuppressLint("NewApi")
private String getRealPathFromURI_API19(Context context, Uri uri) {
return RealPathUtil.INSTANCE.getRealPathFromURI_API19(context, uri);
}
public String getRealPathFromURI(Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = getActivity().managedQuery(contentUri, proj, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
#SuppressLint("NewApi")
private String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
String result = null;
CursorLoader cursorLoader = new CursorLoader(
context,
contentUri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
if (cursor != null) {
int column_index =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
result = cursor.getString(column_index);
}
return result;
}
The thing you are asking for can be done using System Access Frame work.
Add Storage Permissions inside the manifest file, and then check if the permission is accepted or not. Then you can open open document choose to let the user choose the image.
Code
Inside some onClick
Intent i = new Intent(Intent.ACTION_OPEN_DOCUMENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(i, 41);
This will open file chooser activity for image files only.
Then you can get back the results inside:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK){
if (requestCode == 41) {
if (data != null) {
Uri uri = data.getData();
//This is the uri to the file
//To get the file use the uri
}
}
}
}
Still you have to create the BottomSheetDialog on your own, but your job will be drastically reduced as there will be only 2 options : 1. Camera app ,2. File chooser. You will have to handle the camera event on your own and get the image uri.
I suggest using android image Android-Image-Cropper by ArthurHub
It gives you all the options you are looking for

onActivityResult returns with data = null

Ok so this here is the intent I am sending
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
startActivityForResult(intent, REQUEST_CODE);
And then in the onActivityResult I am doing this:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i("Intent name:",data.toString());
if (requestCode == REQUEST_CODE){
if (resultCode == Activity.RESULT_OK){
Toast.makeText(this, "Image saved to \n" + fileUri.toString() , Toast.LENGTH_LONG).show();
Toast.makeText(this, "Result Code: " + resultCode , Toast.LENGTH_LONG).show();
//Bitmap mBitMap = BitmapFactory.decodeFile(data.getData().toString());
//imageView.setImageBitmap(mBitMap);
}
else if (resultCode == RESULT_CANCELED){
Toast.makeText(this, "Capture Cancelled", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(this, "Capture failed", Toast.LENGTH_LONG).show();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
The LogCat is showing a NullPointerException at the line that says Image Saved....
And also this:
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=100, result=-1, data=null}
This happens whether i try to use the data object or the fileUri field of my class.
Why is data being returned null?
Why is it that even though I am using a field of the class i still get the same error?
Whenever you save an image by passing EXTRAOUTPUT with camera intent ie
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
in a file, the data parameter inside the onActivityResult always return null. So, instead of using data to retrieve the image , use the filepath to retrieve the Bitmap.
So onActivityResult would be something like this:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
String[] fileColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(imageUri,
fileColumn, null, null, null);
String contentPath = null;
if (cursor.moveToFirst()) {
contentPath = cursor.getString(cursor
.getColumnIndex(fileColumn[0]));
Bitmap bmp = BitmapFactory.decodeFile(contentPath);
ImageView img = (ImageView) findViewById(R.id.imageView1);
img.setImageBitmap(bmp);
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "Capture Cancelled", Toast.LENGTH_LONG)
.show();
} else {
Toast.makeText(this, "Capture failed", Toast.LENGTH_LONG)
.show();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
Make sure that you have taken imageUri or fileUri as a global variable so that you can access it inside onActivityResult as well. Best of luck
The correct/preferred way to handle data in these cases would be as:
In called Activity set data to the Intent , then setResult code as RESULT_OK and then finish that activity.
In this recieving activity , check the result code.. and retrieve data from Intent variable as :intent.getExtra("... "); //The variables which you have set in the child activity that has been closed now..

Building a Camera App - Receive

I am new to Android programming and I'm writing an application in Java that opens the camera take a photo and save it. I made it via Intents but I can't see onActivityResult running.
I have tested it into my phone (Samsung Galaxy S) and when I take the photo I receive a preview of that photo having two buttons one Save and the other Cancel. I haven't added something to my code to do this so I think it's something that camera does. I want after capturing the image to run onActivityResult (after I press the Save button on the preview).
But how I'm going to return a result to start onActivityResult after pressing the Button Save on the preview?
I FORGOT to tell that after i press save my entire app is terminated.
Here is my Code
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TakePicButton = (Button) findViewById(R.id.TakePicture);
TakePicButton.setOnClickListener((android.view.View.OnClickListener) this);
}
#Override
public void onDestroy(){
super.onDestroy();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Image captured and saved to fileUri specified in the Intent
Toast.makeText(this, "Image saved to:\n" + data.getData(), Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "Picture was not taken", Toast.LENGTH_SHORT);
} else {
Toast.makeText(this, "Picture was not taken", Toast.LENGTH_SHORT);
}
}
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId() == R.id.TakePicture){
// create Intent to take a picture and return control to the calling application
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
// start the image capture Intent
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}
}
try the below code, you will have to modify it a bit, it will help you get From Library and From Camera both, the SELECT_PICTURE is used for getting image from library
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case SELECT_PICTURE:
Uri selectedImageUri = data.getData();
filemanagerstring = selectedImageUri.getPath();
selectedImagePath = getPath(selectedImageUri);
if (selectedImagePath != null)
myFile = new File(selectedImagePath);
else if (filemanagerstring != null)
myFile = new File(filemanagerstring);
if (myFile != null) {
Bitmap bmp_fromGallery = decodeImageFile(selectedImagePath);
break;
case CAMERA_REQUEST:
Bitmap bmp_Camera = (Bitmap) data.getExtras().get("data");
break;
default:
break;
}
}

Categories

Resources