I am an Android newbie and I need to figure out how to return data from one activity to another. The idea is that when a row in a recycler view is clicked, it will load the selected row in another activity. If the row is deleted, then the data row is deleted a list, and the control is returned the activity containing the recycler view. But I am getting the following error.
Process: com.manoflogan.criminalintent, PID: 27222
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid
view holder adapter positionViewHolder{9ed884a position=1 id=-1, oldPos=1,
pLpos:-1 scrap [attachedScrap] tmpDetached no parent}
android.support.v7.widget.RecyclerView{833ff9c VFED..... ......I.
0,0-1080,1584 #7f070032 app:id/crime_recycler_view},
adapter:com.manoflogan.criminalintent.CrimeListFragment$CrimeAdapter@4ad8da5,
layout:android.support.v7.widget.LinearLayoutManager@1abc57a,
context:com.manoflogan.criminalintent.CrimeListActivity@6a147d9
at
android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5715)
at
android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5898)
at
android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
at
android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
at
android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
at
android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1557)
at
android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
at
android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
at
android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3875)
at
android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3639)
at
android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1877)
at
android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:407)
at
android.view.Choreographer$CallbackRecord.run(Choreographer.java:949)
at android.view.Choreographer.doCallbacks(Choreographer.java:761)
at android.view.Choreographer.doFrame(Choreographer.java:693)
at
android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2018-11-24 22:11:30.588 1608-1608/? E/lowmemorykiller: Error writing /proc/2
This is the workflow
When the app starts, the user will see an empty view asking the user to
add a new Crime
by clicking on +
button on the menu. Image # 1. This is the fragment responsible for rendering the home screen.
When +
symbol is clicked, then the user is directed to a [different activity which encapsulates a view
pager that manages a fragment. The user can either click on the back button on the menu bar, or the device back button to see the added entries on the home screen . This is an activity that uses ViewPager to manage multiple Crime objects.
The user can repeat step # 2 to add more *crimes*
.
To delete the crime, the user clicks/taps on any view holder (row) to go to the same activity as seen in step # 2, and then taps on the garbage
icon. The item is then deleted, and the user is redirected back to the view managed by the parent's activity screen. This the block of code that invokes the activity that encapsulates the selected view.
private class CrimeHolder extends RecyclerView.ViewHolder implements
View.OnClickListener {
// Child views instance variables.
public CrimeHolder(View view) {
super(view);
// *. . . Initialising child views . . . *
}
@Override
public void onClick(View view) {
Intent intent = CrimePagerActivity.newIntent(getActivity(),
mCrime.getId());
lastAdapterClickedPosition = getAdapterPosition();
// Invoking another activity. I would like the activity result to be handled by `onActivityResult`.
getActivity().startActivityForResult(intent,
CRIME_VIEW_CODE);
}
void bind(Crime crime) {
mCrime = crime;
// Setting the state of child views
}
}
When the user clicks the delete button, the following menu option is triggered,
@Override
public boolean onOptionsItemSelected(MenuItem item) {
CrimeLab crimeLab = CrimeLab.get(getActivity());
Intent intent = new Intent();
switch(item.getItemId()) {
case R.id.delete_crime:
// Idea is that this index will be instantiated when activity result is returned.
intent.putExtra(CrimeListFragment.DELETE_ROW_INDEX,
crimeLab.getCrimes().indexOf(mCrime));
crimeLab.deleteCrime(mCrime);
getActivity().setResult(Activity.RESULT_OK, intent);
getActivity().finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Here are what I think are my issues.
Ideally, when I have set my result, and have invoked finish
to return to the previous activity, I would like onActivityResult
to be invoked on returning. But that is not the case. Is my understanding correct? Given below is the method that I would have to see called.
// Never invoked.
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
return;
}
if (requestCode == CRIME_ADD_CODE) {
lastInsertedRowPosition =
data.getIntExtra(CrimeListFragment.ROW_INDEX, -1);
} else if (requestCode == CRIME_VIEW_CODE) {
}
}
there are two options first call the startActivityForResult, replace this:
getActivity().startActivityForResult(intent, CRIME_VIEW_CODE);
with
startActivityForResult(intent, CRIME_VIEW_CODE);
the second option you call it with getactivity() but you should override onActivityResult from the activity itself to call onActivityResult of the fragment like this :
In Activity:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Fragment fragment = getSupportFragmentManager().findFragmentById("yourFragment");
fragment.onActivityResult(requestCode, resultCode, data);
}
and this will invoke your onActivityResult of your fragment.
I hope this could help you.