So currently, I'm capturing an image and updating it in a RecyclerView
using the Camera Intent:
private void cameraIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Log.e(TAG, ex.getLocalizedMessage());
}
if (photoFile != null) {
Uri uri = FileProvider.getUriForFile(getActivity().getApplicationContext(),
"packagename.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
What happens prior to this is it'll trigger the intent from an setOnItemClickListener interface
I have created within my RecyclerView.Adapter
which is called in onCreate
to populate the data from the web-server (or when triggered by setVisibleUserHint
as they re-enter the fragment again).
//init camera data
if (isCamera) {
cameraArray = object.getJSONArray(PROFILE_DETAILS_CAMERA_ARRAY_KEY);
sortAdapter(true, object, cameraArray);
} else {
galleryArray = object.getJSONArray(PROFILE_DETAILS_GALLERY_ARRAY_KEY);
sortAdapter(false, object, galleryArray);
}
//settings adapters
cameraAdapter = new RecyclerViewAdapterGallery(getActivity(), array, true);
cameraAdapter.setOnItemClickListener(new RecyclerViewAdapterGallery.onItemClickListener() {
@Override
public void setOnItemClickListener(View view, final int position, String image, final boolean isCamera, boolean isLongClick) {
clickResponse(view, position, image, isCamera, isLongClick, cameraAdapter, array, object);
}
});
recyclerView.setAdapter(cameraAdapter);
cameraAdapter.notifyDataSetChanged();
What happens post is within the onActivityResult
:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_TAKE_PHOTO:
if (resultCode != Activity.RESULT_CANCELED) {
if (resultCode == Activity.RESULT_OK) {
try {
handleBigCameraPhoto(finalPosition);
} catch (IOException e) {
Log.e(TAG, e.getLocalizedMessage());
}
}
}
break;
...
}
}
handleBigCameraPhoto:
private void handleBigCameraPhoto(int position) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
getActivity().sendBroadcast(mediaScanIntent);
saveFile(f, false, position);
}
This works perfectly, it saves the file fine to the web-server but I want to update the adapter when that is successful, and of course I'm unable to restore the adapter object using outState
or inState
bundle.
cameraArray.put(position, parseFile.getUrl());
userObject.put(PROFILE_DETAILS_CAMERA_ARRAY_KEY, cameraArray);
userObject.saveInBackground(new SaveCallback() {
@Override
public void done(ParseException e) {
if (e == null) {
if (cameraAdapter != null) {
cameraAdapter.updatePosition(cameraArray, position);
}
} else {
Log.e(TAG, "failed " + e.getLocalizedMessage());
}
}
});
By this point I'm not sure why the cameraAdapter
isn't updating as it's not returning null and is calling updatePosition().
public void updatePosition(JSONArray array, int position) {
Log.e(TAG, "updatePositionCalled");
this.imageList = array;
notifyItemChanged(position);
}
If anyone can help me solve this mystery, that would be great! Also, if you need any more code or verification at all, let me know.
Note: I currently have the JSONArray
of objects, position in the adapter and web-server object stored in the saveInstanceState
bundle and is restored correctly (because when I come out of the ViewPager
fragment and come back in, thus calling setUserVisibleHint
it restores the adapter from the web-server correctly).
Update: I've created a getImageList()
method inside the adapter and calling that after the supposed 'update', it's updating the list values but not the list?! So i really do think the problem is with notifyItemChanged(position)
public JSONArray getImageList() {
return imageList;
}
// new call
if (e == null) {
cameraAdapter.updatePosition(cameraArray, position);
Log.e(TAG, cameraAdapter.getImageList().toString());
} else {
Log.e(TAG, "failed " + e.getLocalizedMessage());
}
It literally prints out the corresponding values in the list, that has been passed to the adapter, but doesn't seem to update the UI.
Update II:
I've had two (now deleted) answers advising me to notifyDataSetChanged()
, Which makes no difference at all and is counter-productive as it'll rebind the whole adapter within the fragment, thus making it slow. I'm already rebinding the dedicated position (supposedly) with notifyItemChanged()
.
Note II: I'm offering a bounty, not for lazy and unresearched answers but for a solution with the very least an explanation, I'd like to know why it's going wrong, so I don't run into the same problem again (not a quick fix). I'm already well aware of the different functionalities and components of a RecyclerView
, RecyclerView.Adapter
and RecyclerView.ViewHolder
, I'm just having trouble in this particular scenario where the Activity
is returning a result, but not updating the UI as it should.
Hey i think the issue is with the line this.imageList = array
of below method,
public void updatePosition(JSONArray array, int position) {
Log.e(TAG, "updatePositionCalled");
this.imageList = array;
notifyItemChanged(position);
}
Reason :
The this.imageList = array
line is creating a new reference. It is not updating the old reference which was passed in the Recyclerview. Hence, notifyItemChanged(position);
is refreshing the view but with the old reference of the array which has not been updated.
Solution:
You need to update the method as following:
public void updatePosition(String url, int position) {
Log.e(TAG, "updatePositionCalled");
this.imageList.put(position, url);
notifyItemChanged(position);
}
And
userObject.put(PROFILE_DETAILS_CAMERA_ARRAY_KEY, cameraArray);
userObject.saveInBackground(new SaveCallback() {
@Override
public void done(ParseException e) {
if (e == null) {
if (cameraAdapter != null) {
cameraAdapter.updatePosition(parseFile.getUrl(), position);
}
} else {
Log.e(TAG, "failed " + e.getLocalizedMessage());
}
}
});
Update:
Also, replace notifyItemChanged(position)
with notifyItemInserted(position)
as new item is being inserted here in the Array.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With