So I have a fragment with recyclerview in it which is a direct child of my first Activity. In my recyclerview rows I have imagebutton. So for my second activity I have a feature where it can change the image of the imagebutton from my first activity's recyclerview. Can somebody help me?
Update:
My application has an addtocard feature. So in the first activity there's individual imagebutton for every row of my recyclerview. When i tap the imagebutton, the image will change and it will be added to the cart. I also have a database for the cart so the ID's of the product get inserted when it is added. If i tap the recyclerview row it will call the second activity and will display the product. So in the second Activity I also have the add to card feature. The problem is when I add the product in the cart inside the second activity i want to update the recyclerview in my first activity to indicate that it was already added.
You need some kind of shared state where the fragment can read from and the second activity can write into. Since I don't known what you use case is I would suggest that you use SharedPreferences for the first POC implementation.
In the onBindView of the adapter of the fragment you check the preferences for the image to use. It can be a R.whatever.id or a URI pointing to the image. In the second activity you set the key to the image resource depending on your requirements.
Or, this might be a better solution actually, pass the reference to the image in your data source of the adapter. Then whenever you need to update the image write the value in the data source and notify the adapter that there are some changes. If you don't use a content provider and are not observing the data source, then reload the contents in the onResume method of the fragment.
But to provide a more accurate answer we need more informations about your use case and the existing code.
Use Callback or Interface. Tigger it when you click and use that interface method to set the Change the Image. Actually I don't Understand Your Question properly. Can you please provide the Code. So i can give proper Answer. What i understand i gave the Answer.
You should pass your model object and list position to second activity.
FirstActivity.java
private static final int REQUIEST_ITEM_DETAILS = 150;
private void showItemDetails(Item item, int position) {
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra(SecondActivity.EXTRA_ITEM, item);
intent.putExtra(SecondActivity.EXTRA_POSITION, position);
context.startActivityForResult(intent, REQUIEST_ITEM_DETAILS);
}
SecondActivity.java
private Item item;
private int position;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
item = getIntent.getParcelableExtra(EXTRA_ITEM);
position = getIntent.getIntExtra(EXTRA_POSITION, -1);
}
/*
* finish your activity with onBackPressed function. so android device's
* Back button and your finishing operation will be same function.
*/
#Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra(EXTRA_ITEM, item);
intent.putExtra(EXTRA_POSITION, position);
setResult(RESULT_OK, intent);
super.onBackPressed();
}
and in your FirstActivity.java catch onActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ITEM_DETAILS) {
if (resultCode == RESULT_OK) {
int position = data.getIntExtra(SecondActivity.EXTRA_POSITION, -1);
Item item = data.getParcelableExtra(SecondActivity.EXTRA_ITEM);
/* put setItem function to your adapter class. it will just replace given item with in your list item */
adapter.setItem(position, item);
adapter.notifyItemChanged(position);
}
}
}
Related
I've seen some RecyclerView examples that simply modify an item within the click listener. My problem is that I start an activity from a click on an item, and the activity can change or delete the clicked item from the list. So the view needs to be updated after the activity is finished.
This code mostly from another developer passes the serialized item and position of the item to the activity as extra data. The position was intended to use to update the view later.
However, I found these comments:
"Do not treat position as fixed; only use immediately and call holder.getAdapterPosition() to look it up later. RecyclerView will NOT call onBindViewHolder again when the position of the item changes in the data set unless the item itself is invalidated or the new position cannot be determined. For this reason, you should only use the position parameter while acquiring the related data item inside this method, and should NOT keep a copy of it. If you need the position of an item later (eg. in a click listener), use getAdapterPosition() which will have the updated adapter position."
In the Adapter:
#Override
public void onBindViewHolder (#NonNull ItemAdapter.MyViewHolder holder, final int position)
{
final Item item = items.get(position);
holder.itemTitle.setText(item.getTitle());
holder.lay_item.setOnClickListener (new View.OnClickListener () {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, ItemDetailActivity.class);
intent.putExtra("Item", item);
intent.putExtra("position", position);
context.startActivity (intent);
// TODO is this the place to refresh the view?
//holder.getAdapterPosition();
}
});
}
and for the activity:
Item currentItem;
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_detail);
currentItem = (Item)getIntent().getSerializableExtra("Item"));
position = getIntent().getExtras().getInt("position");
...
}
I realize that the object held by the view is serialized into the extra data, so currentObject in the activity is not the same object.
I don't know why they did it like that. If that is the norm, please tell me how the list view is updated for changes to the object in the activity. If that is not the norm, how should it be done?
Therein lies the basis of the question, stated in the title:
How do I get a list in an android RecyclerView to update after an activity that modifies what it was showing?
Within the Activity, there is this click listener for the "save" button to update the database:
btn_save.setOnClickListener (new View.OnClickListener () {
#Override
public void onClick(View v) {
// ... stuff that updates the item attributes from the view elements...
// Save it. It is this object that should then be in the list in the RecyclerView.
try
{
MyApp.getDatabase().updateItem(item);
// TODO: This might work if currentItem was actually the one in the list
//adapter.notifyDataSetChanged();
}
catch (PersistenceException ex)
{
// notify user of failure
Toast.makeText (EditItemActivity.this, getResources().getString(R.string.item_update_fail), Toast.LENGTH_LONG).show ();
finish();
return;
}
Toast.makeText(EditItemActivity.this, getResources().getString(R.string.item_update_success), Toast.LENGTH_LONG).show ();
finish ();
}
});
The adapter was created in the fragment like this (where "rv_items" is the RecyclerView):
adapter = new ItemAdapter(itemList, getActivity());
rv_items.setAdapter(adapter);
The Item class is declared as:
class Item implements Serializable
In general, any time you're talking about "modifying a RecyclerView", that's a hint that you're looking at things the wrong way. You should always think about modifying the data, and then realize that the RecyclerView is just one way to display that data. Of course, you'll need to call methods like notifyDataSetChanged() whenever you modify the data so that the RecyclerView can know to update its display to pick up the changes, but you should still always think about the data first.
That being said, the root of the problem here is that you need some way to uniquely identify your item in your list of data items. Generally, I'd lean towards using some sort of unique ID here (instead of position). Then, when your second activity finishes and returns its result, you can use the ID to update your data list and dispatch the changes to the RecyclerView.
With all that, you'd have something like this:
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == MY_REQUEST) {
if (resultCode == Activity.RESULT_OK && data != null) {
String id = data.getStringExtra("id");
for (int i = 0; i < items.size(); ++i) {
if (items.get(i).getId().equals(id)) {
// the item at position i was updated.
// insert your code here...
// at the end, notify the adapter
adapter.notifyItemChanged(i);
}
}
}
}
}
I am using Recyclerview adapter to populate Recyclerview. After populating Recyclerview from SQLite, If user want to open an recyclerview item need to click on that item and adapter open the related activity. Here is an image which can help you understand easily.
When an activity is open user can delete that post from SQLite by clicking delete button after deleting data recyclerview should dynamically update data.
You can also use StartActivityForResult and use the result of the second activity for delete item in first one.
I mean:
FirstActivity starts SecondActivity waiting for result
SecondActivity sends the result back to FirstActivity. Only if you delete
the item.
Now FirstActivity remove and refresh the list.
In FirstActivity:
Intent i = new Intent(this, SecondActivity.class);
startActivityForResult(i, 1);
In SecondActivity, when you push delete button:
Intent returnIntent = new Intent();
returnIntent.putExtra("delete", true);
returnIntent.putExtra("position", position);
setResult(Activity.RESULT_OK, returnIntent);
finish();
And finally, FirstActivity handle the result:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if(resultCode == Activity.RESULT_OK){
if (data.getBooleanExtra("delete") {
// get position and delete item from list and refresh
int position = data.getIntegerExtra("position");
}
}
if (resultCode == Activity.RESULT_CANCELED) {
//Write your code if there's no result
}
}
}//onActivityResult
https://stackoverflow.com/a/10407371/1820599
Edited:
Getting the context of your activity inside the adapter constructor:
FirstActivity listener;
public myAdapter(Context context, List<String> items) {
super(context, R.layout.row_edition, items);
this.listener = ((FirstActivity) context);
this.items = items;
}
Then, inside the adapter, when you push on item, call the activity to start the seconde one:
listener.startSecondActivity(int position, parameters you need to use);
and finally, in your FirstActivity
startSecondActivity(int position, parameters you need to use) {
// whatever you have to do
Intent i = new Intent(this, SecondActivity.class);
// push position inside intent and whatever you need
startActivityForResult(i, 1);
}
The flow is:
Push item
Use FirstActivityListener to call SecondActivity
In SecondActivity delete and senr result back
In FirstActivity remove item from adapter, using an auxiliar method
inside que adapter
if you display list of companies in recyclerview once you click to show detailes of company and you delete the company once back you should found the item disappear this what my code do
protected void onResume()
{
super.onResume();
Log.i("TAG", "resume");
if(yourlist.size() > 0)
{
yourlist.clear();
yourlist.addAll(where your data come from
ex:databaseHelper.GetOrganization());
youradapter.notifyDataSetChanged();
}
}
You must have to implement a listener in your activity, that tells your recycler view that the items has changed. I suppose that you have implemented your own onItemClickListener for recycler view, so you have position and can easily remove item from recycler view data set. For more info, please, post your code.
This listener goes in your class that populate Recycler view.
public interface DeletedListener {
void deleted(int position);
}
Makes your activity implement this listener, and there send what position have to remove.
public void setListener(DeletedListener listener) {
this.listener = listener;
}
DeletedListener listener;
From your activity call the setListener method, and from adapter, call deleted method.
i have Two list-view activity.
In first list-view activity i have link to open second list-view activity. In Second list-view i have 5 rows. i want to pass the position of second list-view item to first first activity and according to position set text for only second row.
i can pass static data form second list-view activity to first list-view activity with finish(), but i don't know how to set it to selected row and i don't know how to pass position of second list-view with finish().
Anyone can help then please write code. for this
i want to set text for second row of first list-view.also write for this.
Thanks.
You could utilize startActivityForResult() to launch the second activity. By calling that instead of startActivity() your first activity will be noticed when the second one completes.
In your FirstActivity, launch the second activity using this:
Intent launch2ndActivity = new Intent(this, SecondActivity.class);
startActivityForResult(launch2ndActivity, 610);
Then on your SecondActivity:
// Do what do you need to do here.
//I assume you would need to get the position of your ListView upon item click.
..
yourListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent resultIntent = this.getIntent();
resultIntent.putExtra("clicked_row", position);
SecondActivity.this.setResult(RESULT_OK, resultIntent);
finish();
}
});
The last thing you'd need to do is specify how your FirstActivity should react upon recieving the result from SecondActivity:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode) {
case 610:
if (resultCode == RESULT_OK) {
Bundle res = data.getExtras();
int clickedRow = res.getInt("clicked_row");
// Do what you want with that value..
}
break;
}
}
I've got big problem with checkbox. I've got chceckbox in my MainAdapter(not Activity), I'm checking it and go to the next actvity by clicking on button. Then I return from DefaultActivity to MainActivity and I want checkbox to be unchecked. I also add that checkbox's logic is in Adapter in ViewHolder like this :
class ViewHolder {
TextView tv1;
TextView tvC;
ImageView ivT;
CheckBox chb;
}
and all logic is in getView method.If you don't understand something and you want me to help. Just ask what you want to get.
When you start your new Activity, do it calling startActivityForResult(). This will call a callback method once you close your second activity, so this way you make sure you'll enter that method once you finish() your newly opened Activity.
Once in there, simply find your view by id, and uncheck it. This is a sample code:
final Intent intent = new Intent(YourActivityThatContainsListViewDefinition.class, YourNewActivity.class);
startActivityForResult(intent, 1);
Afterwards, just override the onActivityResult() method.
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case 1:
CheckBox cb = (CheckBox) findViewById(R.id.your_checkbox_id);
cb.setChecked(false);
break;
}
}
---- EDIT ----
All this code would be outside your Adapter implementation - so, if you look at the code I provided, in the Intent, the first parameter is the context of the Activity that opens the second one. That means that those two overrides, you have to implement them in the Activity that calls the other (in your case, the MainActivity).
In your second Activity (DefaultActivity), you need to do nothing, just notify the first Activity (MainActivity) that it has to unckeck the CheckBox. To do so, you simply do something like this when you want to close DefaultActivity:
Intent returnIntent = new Intent();
setResult(RESULT_OK, returnIntent);
finish();
This way, you're notifying MainActivity that it should fire onActivityResult() and there's where you uncheck that CheckBox.
To uncheck your checkbox do:
chb.setChecked(false);
if is in adapter you can retrieve it in when getView() is called...
e.g.
holder.chb.setChecked(false);
with this the checkbox will be unchecked every time that de adapter is notified or created again
I'm starting with Android, I could create a ListView and it works perfect. This list contains an image representing a task status (active or inactive), when clicking on a list item opens a new activity where you can modify the task, changing its data or state.
I want to ensure, that when the user returns to the task list, the item for the task which was working will be update (change the image that represents its state).
How can I do that in the activity which works on the selected task?
This is my code that open new activity for selected iten in ListView:
listTareas.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String tarea_id = ((TextView) view.findViewById(R.id.tarea_id)).getText().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(), SingleItemActivity.class);
in.putExtra(TAG_TAREA_ID, tarea_id);
startActivity(in);
}
});
I can send the id of drawable that I want to change, but how can I handle it on SingleItemActivity? Is that possible?
Thank you guys.
Greetings. -
You cannot change the drawable associated with an ID.
You should call startActivityForResult instead of startActivity and then when you return from SingleItemActivity the method onActivityResult will be called. Use this to update your dataset that the ListView populates from.
Once you've updated the data you should call notifyDataSetChanged() on the ListView's adapter.
I think you should use startActivityForResult() instead of startActivity() and you need to override method
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);