loading last chosen image into ImageView after re-entering the app - java

My goal is to make last chosen image to stay in ImageView after an app was closed (destroyed) and then re-opened.
I tried to load to save bitmap in SharedPreference "(How can I store images using sharedpreference in android?), then I tried to store path to bitmap in SharedPreferences and load it using Picasso: (Picasso Load image from filesystem), and tried to load it by passing the value to BitmapFactory.decodeFile(completePath); as you can see in my code.
Anyway the output is always the same; I'm getting an NullPointerException.
I'm new to Android and programming in general so forgive my messy code.
private String picturePass;
private ImageView imageView;
private Bitmap picBitmap;
private boolean yes;
private static final int SELECT_PICTURE = 1;
private static final String SAVE_NAME = "MyFile";)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_activity_page);
if (savedInstanceState != null) {
savedInstanceState.get("path");
}
//loading
SharedPreferences preferences = getSharedPreferences(SAVE_NAME, MODE_PRIVATE);
//boolean to check if Image was chosen
yes = preferences.getBoolean("yes", true);
if(yes){
picturePass = preferences.getString("path", null);
String completePath = picturePass;
//just to check the content
Toast.makeText(this, completePath, Toast.LENGTH_LONG).show();
File file = new File(completePath);
if (file.exists()) {
picBitmap = BitmapFactory.decodeFile(completePath);
imageView.setImageBitmap(picBitmap);
}
}
}
//Choosing a picture from gallery
public void onClickImage(View view) {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, SELECT_PICTURE);
yes = true;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == SELECT_PICTURE && resultCode == RESULT_OK && null != data) {
//The only way I maneged to get the file path, that's a messy part
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
//Setting picture in imageView
if (selectedImage != null) {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);
imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap(bitmap);
picBitmap = bitmap;
//Tried to use Environment.getExternalStorageDirectory().getAbsolutePath() + imageName with no success
//File f = new File(picturePath);
//String imageName = f.getName();
//picturePass = imageName;
picturePass = picturePath;
//Saving image path
//just too check the content
Toast.makeText(this, picturePath, Toast.LENGTH_LONG).show();
SharedPreferences.Editor editor = getSharedPreferences(SAVE_NAME, MODE_PRIVATE).edit();
editor.putString("path", picturePass);
editor.putBoolean("yes", true);
editor.commit();
} catch (Exception ex) {
ex.printStackTrace();
}
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("path", picturePass);
}
}
08-29 19:05:46.263 16436-16436/com.amberapply.vitaliy.iloveyou E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.amberapply.vitaliy.iloveyou, PID: 16436
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.amberapply.vitaliy.iloveyou/com.amberapply.vitaliy.iloveyou.MainActivityPage}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageBitmap(android.graphics.Bitmap)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5258)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:940)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:735)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageBitmap(android.graphics.Bitmap)' on a null object reference
at com.amberapply.vitaliy.iloveyou.MainActivityPage.onCreate(MainActivityPage.java:60)
at android.app.Activity.performCreate(Activity.java:6005)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) 
at android.app.ActivityThread.access$800(ActivityThread.java:151) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5258) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:940) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:735) 

#Nikunj Sardhara solution should work
if you fix the npe : in onCreate there is no imageView = (ImageView) findViewById(R.id.imageView); before `imageView.setImageBitmap(picBitmap);

First of all storing an image in SharedPreferences would be a very bad idea.
You should store path of image in SharedPreferences and you can read that image when your app loads for the first time, read the SharedPreferences, get your image path, read it from storage and show it in your ImageView.
So, that was the procedure and that is simple, It does't require writing this much code.
Now you don't really need to store boolean in SharedPreferences, you can use contains() method :
https://developer.android.com/reference/android/content/SharedPreferences.html
And about NullPointerException, i would say please check logcat and if possible then copy your logcat at the time of NullPointerException and post your logcat here, that would be more helpful.
Here's how you can get logcat : https://developer.android.com/studio/debug/am-logcat.html

Related

Android: Choosing the right settings to prepare ActivityResultLauncher for picking contacts

After 4 hours of trying and reading the documentation I cannot resolve problems getting Uri data when using ActivityResultLauncher in place of my working but deprecated solution of picking contacts and contentResolver to use the data.
The copied code at least enables me to successfully pick a contact using the launched intent, but applying [...data.setData((Uri) uriData)...] results in a NULL pointer exception for getContentResolver.
I have tried declaring ActivityResultLauncher as a String and as Uri with ActivityResultContracts.GetContent() but when I think I am close, I cannot find the right parameters to launch the ContactContracts.... PickContact as it has no MIME, but with using intent, I cannot get a Uri result. Guess that's why they only document the easy solutions on the Developer site, such as picking an image MIME.
Public class InvoiceFragment extends Fragment implements InvoiceListAdapter.OnInvoiceItemListener{
private InvoiceListAdapter iAdapter;
private SubTotalListAdapter sAdapter;
private Locale locale = new Locale("en", "UK");
private NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(locale);
Float invoiceTotal;
RecyclerView.LayoutManager invLayoutManager;
DatabaseHelper myDb;
final Uri uriData = null;
//ArrayList<InvoiceItem> invoiceItemList = new ArrayList<>();
ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
Intent data = result.getData();
data.setData((Uri) uriData);
Cursor c = getContext().getContentResolver().query(uriData, null, null, null, null);
if(c.moveToFirst()){
String name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Log.d(TAG, "onActivityResult: " + name);
c.close();
}
}
});
Then Launching it!
view.findViewById(R.id.btGetContact).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (checkPermissions(getActivity(), READ_CONTACTS)) {
Intent contactsIntent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
//contactsIntent.setData((Uri) uriData);
mStartForResult.launch(contactsIntent);
}
}
});
Results in
java.lang.RuntimeException: Unable to resume activity {wytonmcs.com.accounts/wytonmcs.com.accounts.InvoiceActivity}: java.lang.NullPointerException: uri
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3581)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3621)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1638)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.NullPointerException: uri
at com.android.internal.util.Preconditions.checkNotNull(Preconditions.java:128)
at android.content.ContentResolver.query(ContentResolver.java:737)
at android.content.ContentResolver.query(ContentResolver.java:704)
at android.content.ContentResolver.query(ContentResolver.java:662)
at wytonmcs.com.accounts.InvoiceFragment$1.onActivityResult(InvoiceFragment.java:70)
at wytonmcs.com.accounts.InvoiceFragment$1.onActivityResult(InvoiceFragment.java:62)
at androidx.activity.result.ActivityResultRegistry$1.onStateChanged(ActivityResultRegistry.java:145)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:265)
at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:307)
at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:148)
at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
at androidx.fragment.app.Fragment.performStart(Fragment.java:3013)
at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:586)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:300)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1636)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3112)
at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:3063)
at androidx.fragment.app.FragmentController.dispatchStart(FragmentController.java:262)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:482)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1334)
at android.app.Activity.performStart(Activity.java:7029)
at android.app.Activity.performRestart(Activity.java:7104)
at android.app.Activity.performResume(Activity.java:7109)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3556)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3621) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1638) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:164) 
at android.app.ActivityThread.main(ActivityThread.java:6494)
In your OnClick call the launch with null, mStartForResult.launch(null);
and you can use ActivityResultContracts.PickContact()
ActivityResultLauncher<String> mStartForResult = registerForActivityResult(new ActivityResultContracts.PickContact(),
new ActivityResultCallback<Uri>() {
#Override
public void onActivityResult(Uri uri) {
Cursor c = getContext().getContentResolver().query(uri, null, null, null, null);
if(c.moveToFirst()){
String name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Log.d(TAG, "onActivityResult: " + name);
c.close();
}
}
});
There are some examples in a youtube video called: ActivityResultContracts Android

Get Real Path of mp3 file from Uri

I have picked audio file from Content Picker intent inside Fragment which extend PreferenceFragmentCompat
Intent intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setType("audio/mpeg");
startActivityForResult(intent, 1);
and Retrieved Uri from onActivityResult
#Override
public void onActivityResult(int requestCode, int resultcode, Intent data) {
if (requestCode == 1 && resultcode == Activity.RESULT_OK) {
audio = data.getData();
inputfile= (FileInputStream getActivity().getApplicationContext().getContentResolver().openInputStream(data.getData());
}
super.onActivityResult(requestCode, resultcode, data);
}
Where audio is declared public(Uri audio).
Now i wanted this audio file to be copied to a Directory in App Directory(/data/data/com.example.focusit).For this i need to get Real path of audio file from URI
public String getRealPathFromUri(Uri contentUri) {
String res = null;
String[] proj = {
MediaStore.Audio.Media.DATA
};
Cursor cursor = (Cursor) getActivity().getApplicationContext().getContentResolver().query(contentUri, proj, null, null, null);
if (cursor.moveToFirst()) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
res = cursor.getString(column_index);
}
cursor.close();
return res;
}
Now to copy audio file to my directoy i used this code
File audiofile = new File(audio.getPath());
String realpath = getRealPathFromUri(audio);
File file = new File("/data/data/com.example.focusit/Focusit_SOS/tt_temp.mp3");
if (!file.exists()) {
Toast.makeText(getContext(), "Director focus it does not existed", Toast.LENGTH_SHORT).show();
file.mkdirs();
}
try {
FileUtils.copy(new FileInputStream(audiofile), new FileOutputStream(file));enter code here
} catch (IOException e) {
e.printStackTrace();
But problem is that in function getRealPathFromUri(Uri ContentUri) cursor.movetoFirst() is returning false.Any idea how to deal with it.
Output of audio.getpath() is /external/audio/media/8099.
i tried one solution by creating Input stream directly from Uri in onActivityResult()
inputfile= (FileInputStream) getActivity().getApplicationContext().getContentResolver().openInputStream(data.getData());
but i am getting exception
2020-10-28 07:41:31.333 21292-21292/com.example.focusit E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.focusit, PID: 21292
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=65537, result=-1, data=Intent { dat=content://media/external/audio/media/8099 (has extras) }} to activity {com.example.focusit/com.example.focusit.SettingsActivity}: java.lang.SecurityException: com.example.focusit has no access to content://media/external/audio/media/8099
at android.app.ActivityThread.deliverResults(ActivityThread.java:4905)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4946)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2040)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7520)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: java.lang.SecurityException: com.example.focusit has no access to content://media/external/audio/media/8099
at android.os.Parcel.createException(Parcel.java:2074)
at android.os.Parcel.readException(Parcel.java:2042)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:188)
at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:151)
at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:705)
at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1702)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1518)
at android.content.ContentResolver.openInputStream(ContentResolver.java:1202)
at com.example.focusit.SettingsActivity$SettingsFragment.onActivityResult(SettingsActivity.java:227)
at androidx.fragment.app.FragmentActivity.onActivityResult(FragmentActivity.java:170)
at android.app.Activity.dispatchActivityResult(Activity.java:8249)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4898)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4946) 
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2040) 
at android.os.Handler.dispatchMessage(Handler.java:107) 
at android.os.Looper.loop(Looper.java:224) 
at android.app.ActivityThread.main(ActivityThread.java:7520) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950) `
Providing Storage access will resolve Exception
java.lang.SecurityException: com.example.focusit has no access to content:
Do not open a FileInputStream on a path you do not have.
Instead open an InputStream on the obtained uri directly.
InputStream is = getContentResolver().openInputStream(data.getData());

java.lang.RuntimeException: Unable to resume activity Attempted to access a cursor after it has been closed

I have following method to pass selected image path to another activity:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
Log.d("fsd", "onActivityResult: ");
Intent intent = new Intent(getApplicationContext(), AddContentImage.class);
Bundle b = new Bundle();
b.putString("path", selectedImagePath);
intent.putExtras(b);
startActivity(intent);
}
}
}
Which is actually working fine, but I gets following error, when back button is pressed.
java.lang.RuntimeException: Unable to resume activity : android.database.StaleDataException: Attempted to access a cursor after it has been closed.
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3169)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3247)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1440)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5582)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: android.database.StaleDataException: Attempted to access a cursor after it has been closed.
at android.database.BulkCursorToCursorAdaptor.throwIfCursorIsClosed(BulkCursorToCursorAdaptor.java:63)
at android.database.BulkCursorToCursorAdaptor.requery(BulkCursorToCursorAdaptor.java:132)
at android.database.CursorWrapper.requery(CursorWrapper.java:228)
at android.app.Activity.performRestart(Activity.java:6363)
at android.app.Activity.performResume(Activity.java:6389)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3158)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3247)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1440)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5582)
This error only occurs if second activity is opened from onActivityResult.
Edited:
getpath method
public String getPath(Uri uri) {
// just some safety built in
if( uri == null ) {
// TODO perform some logging or show user feedback
return null;
}
// try to retrieve the image from the media store first
// this will only work for images selected from gallery
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if( cursor != null ){
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(column_index);
cursor.close();
return path;
}
// this is our fallback here
return uri.getPath();
}
How can I solve this error?
First, managedQuery() has been deprecated for over six years. Do not use it. Use a CursorLoader, or use ContentResolver and query() on some form of background thread.
Second, be sure to follow the instructions of the things that you use. In this case, you missed the instructions for using managedQuery():
Warning: Do not call close() on a cursor obtained using this method, because the activity will do that for you at the appropriate time.
Beyond that, a Uri does not point to a file in most cases, and so you cannot get a "real path" to that file.

Cursor error - Retrieving image from gallery

Currently I'm trying to retrieve the location of an image in my gallery and convert it into a File so that I can upload it to the internet. But I received this error instead. The error happened when I open the gallery and on selecting the image it crash instead. I'm not so well versed in android and still consider myself a beginner. So if you decided to vote down my question please tell me the reason why so that I can learn. Thank you.
Logcat :-
05-07 08:11:45.052 8697-8697/com.example.megasap.jobforhire_android E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.megasap.jobforhire_android, PID: 8697
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content://com.android.providers.media.documents/document/image:34 flg=0x1 }} to activity {com.example.megasap.jobforhire_android/com.example.megasap.jobforhire_android.ProfileEditActivity}: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
at android.app.ActivityThread.deliverResults(ActivityThread.java:3699)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742)
at android.app.ActivityThread.-wrap16(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetString(Native Method)
at android.database.CursorWindow.getString(CursorWindow.java:438)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51)
at android.database.CursorWrapper.getString(CursorWrapper.java:137)
at com.example.megasap.jobforhire_android.ProfileEditActivity.getRealPathFromURI(ProfileEditActivity.java:233)
at com.example.megasap.jobforhire_android.ProfileEditActivity.onActivityResult(ProfileEditActivity.java:191)
at android.app.Activity.dispatchActivityResult(Activity.java:6428)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3695)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742) 
at android.app.ActivityThread.-wrap16(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5417) 
The code that I used to retrieved the image is down below:-
private String getRealPathFromURI(Uri contentURI) {
String result;
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file path
result = contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
result = cursor.getString(idx); // getting error here ; it returns -1
cursor.close();
}
return result;
}
You have to add column name MediaStore.Images.Media.DATA with query.
Update getRealPathFromURI() as below:
private String getRealPathFromURI(Uri contentURI) {
String result;
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(contentURI, filePathColumn, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file path
result = contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(filePathColumn[0]);
result = cursor.getString(idx);
cursor.close();
}
return result;
}
In you onActivityResult() method:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try {
// When an Image is picked
if (requestCode == YOUR_REQUEST_CODE && resultCode == RESULT_OK
&& null != data) {
// Get the Image from data
Uri selectedImage = data.getData();
// Get real path
String imageRealPath = getRealPathFromURI(selectedImage);
// Do something
}
} catch (Exception e) {
Toast.makeText(this, "Something went wrong", Toast.LENGTH_LONG)
.show();
}
}
Make sure you have added permission:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Here is a good tutorial. Hope this will help~
You should not try to get a file path and construct a file object from that uri to upload the file. You dont need that all. Use the uri directly to open an inputstream.
Somewhere you will now have
FileInputStream fis = new FileInputStream(path);
Replace that by
InputStream is = getContentResolver().openInputStream(data.getData());
This supports APIs below and above 19, including 19:
public String getRealPathFromURI(Uri uri) {
Cursor cursor = this.getContentResolver().query(uri, null, null, null, null);
String result;
// for API 19 and above
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
cursor.moveToFirst();
String image_id = cursor.getString(0);
image_id = image_id.substring(image_id.lastIndexOf(":") + 1);
cursor.close();
cursor = this.getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{image_id}, null);
}
cursor.moveToFirst();
result = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
return result;
}

java OutOfMemoryError: bitmap size exceeds VM budget

I have ImageView & one button on my ImageActivity. when the button is clicked the available images are listed, when one of them is clicked, it is loaded into the ImageView.
imageView xml:
<ImageView
android:id="#+id/imageView"
android:layout_width="300dip"
android:layout_height="300dip"
android:src="#android:drawable/alert_light_frame"
/>
Please see the code:
public class ImageActivity extends Activity {
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
private ImageView imageView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.comments_detail);
imageView = (ImageView) findViewById(R.id.imageView);
((Button) findViewById(R.id.BtnBrowse))
.setOnClickListener(new OnClickListener()
{
public void onClick(View arg0)
{
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"), SELECT_PICTURE);
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK)
{
if (requestCode == SELECT_PICTURE)
{
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
//System.out.println("Image Path : " + selectedImagePath);
imageView.setImageURI(selectedImageUri);
}
}
}
public String getPath(Uri uri)
{
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
Issue: The issue is that when i click the button the available images are displayed, i selects one of them & it is loaded in the ImageView, when i repeat these steps few time the application throws throws the exception:
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
I goggled it & found that this issue is because of memory leaks but i am unable to find whats wrong with my code. Can anyone spend some of his valuable time to help me?
Thanks.
If you do a series of setImageURIs, you are loading a series of bitmaps into the view. If you are getting the java.lang.OutOfMemoryError: bitmap size exceeds VM budget exception, that implies that the imageView does not recycle the previous bitmap when you load a new one. So you
either need to encourage the imageView to recycle the previous bitmap - possibly with setImageView("")
or get the bitmap from the URI and use setImageBitmap(android.graphics.Bitmap) instead; then you can do setImageBitmap(null) and bitmap.recycle().
Well calling the system.gc() worked!!
Before the image is assigned to the imageView, i called the System.gc(), to take care of memory & it works.
Look at the modified code:
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK)
{
if (requestCode == SELECT_PICTURE)
{
// calling GC to take care of memory, if you remove this one line of code
// application will throw the error "VM out of memory error"
System.gc();
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
imageView.setImageURI(selectedImageUri);
}
}
}
Thanks #Torid.
Can someone comment on it? is this correct way to call the GC in this situation?

Categories