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

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

Related

google tells me that my app crashes on (only) Google Pixel 2 (virtuel)

I'm trying to publish my app in google play console.
But it tells me that it crashes on Google Pixel 2 (virtuel) (works on the 9 others) with 2 errors (very similar)
Google Pixel 2 (virtuel) 1080x1920 Android 12 (SDK 31) - x86_64 en_US
Error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.activity.result.ActivityResultLauncher.launch(java.lang.Object)' on a null object reference
Detail:
FATAL EXCEPTION: Thread-2
Process: xxxxxxxx, PID: 8724
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.activity.result.ActivityResultLauncher.launch(java.lang.Object)' on a null object reference
at xxxxxxxx.models.StockInputDialog.lambda$init$9$xxxxxxxx-models-StockInputDialog(StockInputDialog.java:417)
at xxxxxxxx.models.StockInputDialog$$ExternalSyntheticLambda9.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7441)
at android.view.View.performClickInternal(View.java:7418)
at android.view.View.access$3700(View.java:835)
at android.view.View$PerformClick.run(View.java:28676)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at androidx.test.espresso.base.Interrogator.loopAndInterrogate(Interrogator.java:10)
at androidx.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:7)
at androidx.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:1)
at androidx.test.espresso.base.UiControllerImpl.injectMotionEvent(UiControllerImpl.java:5)
at androidx.test.espresso.action.MotionEvents.sendUp(MotionEvents.java:6)
at androidx.test.espresso.action.MotionEvents.sendUp(MotionEvents.java:1)
at androidx.test.espresso.action.Tap.sendSingleTap(Tap.java:5)
at androidx.test.espresso.action.Tap.-$$Nest$smsendSingleTap(Unknown Source:0)
at androidx.test.espresso.action.Tap$1.sendTap(Tap.java:1)
at androidx.test.espresso.action.GeneralClickAction.perform(GeneralClickAction.java:4)
at androidx.test.espresso.ViewInteraction$SingleExecutionViewAction.perform(ViewInteraction.java:2)
at androidx.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:21)
at androidx.test.espresso.ViewInteraction.-$$Nest$mdoPerform(Unknown Source:0)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:6)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:1)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
My code is explained (and the reason why) startActivityForResult migration, call registerForActivityResult outside activity, and simplified to the maximum:
public class StockActivity extends AppCompatActivity implements DialogCloseListener {
private ActivityResultLauncher<Intent> stockGalleryActivityResultLauncher;
private ActivityResultLauncher<Intent> stockCameraActivityResultLauncher;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
stockCameraActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
result -> {
// code
});
stockGalleryActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
result -> {
// code
});
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
if (id == R.id.action_add) {
mStockInputDialog = new StockInputDialog(this, stockCameraActivityResultLauncher, stockGalleryActivityResultLauncher,);
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
}
public class StockInputDialog {
private final Context mContext;
private AlertDialog mInputDialog;
private ActivityResultLauncher<Intent> stockCameraActivityResultLauncher;
private ActivityResultLauncher<Intent> stockGalleryActivityResultLauncher;
public StockInputDialog(Context context, ActivityResultLauncher<Intent> pStockCameraActivityResultLaunchera, ActivityResultLauncher<Intent> pStockGalleryActivityResultLauncher) {
mContext = context;
stockCameraActivityResultLauncher = pStockCameraActivityResultLaunchera;
stockGalleryActivityResultLauncher = pStockGalleryActivityResultLauncher;
LayoutInflater li = LayoutInflater.from(this.mContext);
mPromptsView = li.inflate(R.layout.text_input_stock, null);
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this.mContext);
alertDialogBuilder.setView(mPromptsView);
final ImageButton imgButtonCam = mPromptsView.findViewById(R.id.addCam);
final ImageButton imgButtonGal = mPromptsView.findViewById(R.id.addGal);
imgButtonCam.setOnClickListener(view -> {
Uri uri = FileProvider.getUriForFile(mContext, "fr.foo.bar.provider",
new Product(Consts.TEMP_NUM).getIMGPathCacheFile(mContext));
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
stockCameraActivityResultLauncher.launch(intent); <= ERROR
});
imgButtonGal.setOnClickListener(view -> {
stockGalleryActivityResultLauncher.launch(new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)) <= ERROR
});
}
}
The 2 errors correspond to the 2 launch()
What I don't understand is that I'm using this same principle elsewhere in the application without an error being raised.
No more crashes when testing the "nullity" of the launchers (#Abdo21 2nd answer).
imgButtonCam.setOnClickListener(view -> {
Uri uri = FileProvider.getUriForFile(mContext, "fr.novazur.donteat.provider",
new Product(Consts.TEMP_NUM).getIMGPathCacheFile(mContext));
if (stockCameraActivityResultLauncher != null)
stockCameraActivityResultLauncher.launch(uri);
else
Toast.makeText(mContext, R.string.featureAbsent, Toast.LENGTH_LONG).show();
});
imgButtonGal.setOnClickListener(view -> {
if (stockGalleryActivityResultLauncher != null)
stockGalleryActivityResultLauncher.launch("image/*");
else
Toast.makeText(mContext, R.string.featureAbsent, Toast.LENGTH_LONG).show();
});
That's what I should have done from the start. I'm a little sorry for not having thought of it, it's so obvious. I guess it's related to the creation of the AlertDialog which should not allow immediate access to the launchers. What I don't understand in this case is why only the Pixel 2 crashes, but problem seems to be solved for the moment. Thanks all.

Null Error attempting to create an intent in AsyncTask

Apologizes if this is a stupid question but I'm attempting to create a Intent to the next activity in AsynTask after it has pulled a user from my AWS Database. Note that this class is HomeActivity and the next one is GroupActivity. Below I have the button that will run the AsynTask:
Button groupPageBtm = findViewById(R.id.groupPage);
groupPageBtm.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
LoadGroupUser loadGroupUser = new LoadGroupUser(HomeActivity.this);
loadGroupUser.execute(makeUserIDString.uniqueIDCreater(userProfile));
}
});
Here is my AsynTask subclass:
class LoadGroupUser extends AsyncTask<String, Void, GroupDO>{
private DynamoDBMapper dynamoDBMapper;
Activity activity;
public LoadGroupUser(Activity mActivity){
this.activity = mActivity;
}
Intent groupLoadIntent = new Intent(activity, GroupActivity.class);
#Override
protected GroupDO doInBackground(String... groupPresidentGroups) {
AmazonDynamoDBClient dynamoDBClient = new AmazonDynamoDBClient(AWSMobileClient.getInstance().getCredentialsProvider());
this.dynamoDBMapper = DynamoDBMapper.builder()
.dynamoDBClient(dynamoDBClient)
.awsConfiguration(AWSMobileClient.getInstance().getConfiguration())
.build();
GroupDO groupPresDO = dynamoDBMapper.load(GroupDO.class, groupPresidentGroups[0]);
Log.i("loadedPresident: ", groupPresDO.getGroupId().toString());
return null;
}
#Override
protected void onPostExecute(GroupDO groupDO) {
super.onPostExecute(groupDO);
groupLoadIntent.putExtra("groupPresident", groupDO.getGroupPresident().toString());
activity.startActivity(groupLoadIntent);
Log.i("groupPresident", groupDO.getGroupPresident().toString());
}
}
Error Message:
-12 17:02:59.424 10503-10503/com.ronone.securesender E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ronone.securesender, PID: 10503
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.content.ComponentName.<init>(ComponentName.java:130)
at android.content.Intent.<init>(Intent.java:5780)
at com.ronone.securesender.LoadGroupUser.<init>(HomeActivity.java:188)
at com.ronone.securesender.HomeActivity$1.onClick(HomeActivity.java:77)
at android.view.View.performClick(View.java:6294)
at android.view.View$PerformClick.run(View.java:24770)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
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)
The problem is here:
public LoadGroupUser(Activity mActivity){
this.activity = mActivity;
}
Intent groupLoadIntent = new Intent(activity, GroupActivity.class);
The field initializer runs before the constructor, so activity is still null. Do this instead:
Intent groupLoadIntent;
public LoadGroupUser(Activity mActivity){
this.activity = mActivity;
groupLoadIntent = new Intent(activity, GroupActivity.class);
}
But note that you're potentially leaking your activity by having a strong reference to it in an AsyncTask. That's a whole other topic. Search this site for "AsyncTask activity leak."

Failed to retrieve ArrayList from a separate class [duplicate]

This question already has answers here:
Initialization of an ArrayList in one line
(34 answers)
Closed 5 years ago.
I have a DataHandaling class that is used to do the logic, it is also suppose to be an easier way to retrieve an ArrayList from multiple activities, But when I start a new activity the ArrayList is null
(NOTE: The array is not empty because I have used the same array multiple times in the main activity, this problem is only a case when I start a new activity)
The code from DataHandaling
public class DataHandaling {
EnviroClass enviroClass = new EnviroClass();
private ArrayList<Event> eventArray = new ArrayList<Event>();
public ArrayList<Event> getEventArray() {
return eventArray;
}
public void getEvents() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(enviroClass.url() + "/api/events/" + 7)
.build();
client.newCall(request)
.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
JSONObject eventObject = new JSONObject(response.body().string());
JSONArray eventJsonArray = eventObject.getJSONArray("events");
for (int i = 0; i<eventJsonArray.length(); i++) {
eventObject = eventJsonArray.getJSONObject(i);
eventObject = eventObject.getJSONObject("event");
eventArray.add(new Event(eventObject.getString("name"), eventObject.getString("address"), eventObject.getString("image"), "100" ,eventObject.getString("start_date"), eventObject.getString("end_date"), eventObject.getInt("id")));
}
EventListAdapter adapter = new EventListAdapter(null, null);
adapter.swap(eventArray);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
}
This is where it is breaking in the new activity
textView.setText(dh.getEventArray().get(0).getName());
The interaction listener to open the new activity
#Override
public void onListFragmentInteraction(int id) {
Intent intent = new Intent(MainActivity.this, ProfileActivity.class);
intent.putExtra("id", id);
MainActivity.this.startActivity(intent);
}
The activity where it is breaking
public class ProfileActivity extends AppCompatActivity {
DataHandaling dh = new DataHandaling();
int eventArrayId;
TextView eventDescription;
TextView eventName;
ImageView eventImage;
ArrayList<Event> eventArray = new ArrayList<Event>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
getSupportActionBar().setHomeButtonEnabled(true);
Intent intent = getIntent();
eventArrayId = intent.getIntExtra("id", 0);
eventName = (TextView) findViewById(R.id.eventNameTextView);
eventName.setText(dh.getEventArray().get(0).getName());
}
}
Stack Trace:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.app.gb.socilizer_app/com.app.gb.socilizer.Activities.ProfileActivity}: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.get(ArrayList.java:411)
at com.app.garethbecker.socializer.Activities.ProfileActivity.onCreate(ProfileActivity.java:39)
at android.app.Activity.performCreate(Activity.java:6679)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) 
at android.app.ActivityThread.-wrap12(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:6119) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
 
You are creating new object of DataHandling in the activity. So it will not be the same object that you had previously used and which has data in it.
First :- If your ArrayList<Event> is empty and if you get 0th index element then you'll get NullPointerException while Executing this line :- dh.getEventArray().get(0).getName() so it is replaced by null.getName() which will break.
So if you want to get index basis Element form collection firsat checkl whether the Collection is empty or not.
Like this:-
//if the ArrayList is not Empty then only iterate over it.
if(!dh.getEventArray().isEmpty())
{
textView.setText(dh.getEventArray().get(0).getName());
}
Second:- Check the logic for adding the Event In ArrayList<Event>.
Your method is called getArray(), yet you're invoking getEventArray(). Maybe it is the reason.
EDIT: Now that your message is edit we have something to work on.
DataHandaling dh = new DataHandaling();
This is a new DataHandaling object, and never in your code you're updating him. So I guess that its ArrayList is empty by default.

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.

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

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

Categories