Reputation: 1649
I have a RecyclerView list with CardViews that is working fine. The CardViews are created when a user enters data on an input UI called ActActivity. When the user later clicks on a CardView to edit the original data, the onItemClick method launches ActActivity again using the start method that captures the correct CardView item position in the Adapter.
When the user clicks on a Save button on the UI to save the edited data, the ActActivity UI closes and the RecyclerView list is automatically re-loaded (MainActivity) and the updated CardView is shown in the RecyclerView list. My problem is the RecyclerView upon re-loading always scrolls to the top of the CardView item list. I would like the list to return to the original CardView that was clicked on to be edited. I somehow need to take the original item position in the Adapter and pass that back to the RecyclerView when it is re-created. And I need to let the RecyclerView know that the position is for a CardView that was just edited not a new CardView. Any ideas on how to accomplish?
MainActivity.java:
public class MainActivity extends AppCompatActivity
...
void loadData(){
SQLiteDB sqLiteDB = SQLiteDB.getInstance(this);
List<Contact> contactList = new ArrayList<>();
Cursor cursor = sqLiteDB.retrieve();
Contact contact;
cursor...
Adapter.addAll(contactList);
@Override
public void onItemClick(int position, final View view) {
cardview = (CardView) view;
ActActivity.start(this, Adapter.getItem(position));
}
ActActivity.java:
public class ActActivity extends AppCompatActivity {
...
private Contact contact;
public static void start(Context context){
Intent intent = new Intent(context, ActActivity.class);
context.startActivity(intent);
}
public static void start(Context context, Contact contact){
Intent intent = new Intent(context, ActActivity.class);
// From the OnItemClick method in the MainActivity the RecyclerView item
// position from the Adapter is passed into a putExtra bundle that the
// intent carries to this Activity. The data is then copied in the onCreate()
// below using getIntent().getParcelableExtra(). So this is to update an
// existing CardView item.
intent.putExtra(ActActivity.class.getSimpleName(), contact);
context.startActivity(intent);
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layout.activ_act);
// Fetch data from a parcelable object passed from the MainActivity.
contact = getIntent().getParcelableExtra(ActActivity.class.getSimpleName());
...
// Update edited EditText lines to the data Model via contact
contact.setDataInput(xEditText.getText().toString());
// Update the data in the SQLite database.
sqLiteDB.update(contact);
ActActivity.this.finish();
Adapter.java:
public class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Contact> contactList;
public Adapter(Context context) {
this.context = context;
this.contactList = new ArrayList<>();
}
Logcat output:
RuntimeException: Unable to resume activity {com.example.jdw.v53/com.wimso.v053.MainActivity}: java.lang.NullPointerException at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2575) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4745) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException at com.wimso.v053.MainActivity.onResume(MainActivity.java:370) at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1184) at android.app.Activity.performResume(Activity.java:5082) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2565) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4745) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method)
Upvotes: 0
Views: 1088
Reputation: 1694
You can start ActActivity
class using context.startActivityForResult(intent,REQUEST_CODE);
as shown below
public static void start(Context context, Contact contact,int position){
Intent intent = new Intent(context, ActActivity.class);
// From the OnItemClick method in the MainActivity the RecyclerView item
// position from the Adapter is passed into a putExtra bundle that the
// intent carries to this Activity. The data is then copied in the onCreate()
// below using getIntent().getParcelableExtra(). So this is to update an
// existing CardView item.
intent.putExtra(ActActivity.class.getSimpleName(), contact);
intent.putExtra("position", position);
context.startActivityForResult(intent,2);
}
once the ActActivity has finished saving the data, you can set the adapter position in the result back to main Activity using setResult(intent)
and once you get the Result in onActivityResult()
in your MainActivity, you will come to know that you have come back after editing, so then you can use this method to scroll to the position ,as shown below
// Call Back method to get the Message form other Activity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// check if the request code is same as what is passed here it is 2
if(requestCode==2)
{
int position=data.getIntExtra("position", 0);
//do all your adapter resetting here for recyclerView
linearLayoutManager.scrollToPositionWithOffset(position, 0);
}
}
Upvotes: 1
Reputation: 6114
In order to do so, the first step is when the user click a card, save its position in your preferred storage option, then while reloading the RecyclerView
you can smooth scroll to the particular position. To do so you'll need to create a custom LinearLayoutManager
. This is how you do it:
public class LinearLayoutManagerWithSmoothScroller extends LinearLayoutManager {
public LinearLayoutManagerWithSmoothScroller(Context context) {
super(context, VERTICAL, false);
}
public LinearLayoutManagerWithSmoothScroller(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) {
RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private class TopSnappedSmoothScroller extends LinearSmoothScroller {
public TopSnappedSmoothScroller(Context context) {
super(context);
}
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return LinearLayoutManagerWithSmoothScroller.this
.computeScrollVectorForPosition(targetPosition);
}
@Override
protected int getVerticalSnapPreference() {
return SNAP_TO_START;
}
}
}
Then assign this to your RecyclerView
and invoke smoothScrollToPosition()
.
recyclerView.setLayoutManager(new LinearLayoutManagerWithSmoothScroller(context));
recyclerView.smoothScrollToPosition(position);
Upvotes: 0
Reputation: 1994
Do the following steps - 1. Keep a track of the adapter position of the card (clickPosition) that the user clicked to edit. This you can keep via a state variable in the MainActivity.
recyclerView.scrollToPosition(*clickPosition*)
Ofcourse, this will work pertaining to the following conditions - 1. The recycler view data set was not concurrently modified while you were in ActActivity. 2. If it is a New Card or Delete Card action, may be the handling would have to be done in a slightly different manner
Upvotes: 1