Comunication through Adapter to notifyDataSetChanged() - android

I implemented the situation described in the image below:
The question is:
I have to update the gridView 2 when I update the GridView 1, how's the best way to do this? I could update the GridView 2 only in its Adapter by do a new Volley Request, maybe I could do this by re-set the adapter in the Fragment 2, Could I use a reference to the Fragment 2 in the Adapter GridView 1 ?
Details:
The GridView 1 is updated by a notifyDataSetChanged() on the Adapter performed after a Volley request by the Adapter itself. I can't use the onResume() method of Fragment 2 because it's not called due to this fragment it's showed at the same time of the Fragment 1.
Any Idea?
Thanks.

A listener is just an interface in JAVA. So you can not create an object of an interface ("new" operator)
1) Create an interface
public Interface OnUpdateGridView2Listener{
public void onUpdate() //Add the kind of data you want in the parameters
}
2) Create a member of the interface in the adapter of gridView1 and call its method
public GidViewAdapter1 extends Adapter{
private OnUpdateGridView2Listener myListener;
//Your code
#Override
public void notifyDataSetChanged(){
//Your code
myListener.onUpdate();
}
public void setOnUpdateGridView2Listener(OnUpdateGridView2Listener list){
this.myListener = list;
}
}
3) Implement the interface in your fragment and notify the adapter
public FragmentGridView2 extends Fragment implements OnUpdateGridView2Listener{
#Override
public void onUpdate(){
//Your code
gridView2Adapter.notifyDataSetChanged();
}
}
4) In your activity, set the listener when you create your fragmentGridView1
public YourActivity{
//Your code
FragmentGridView1 fragment = new FragmentGridView1();
fragment.setOnUpdateGridView2Listener(getApplication());
}

You could try to implement a Listener pattern like this:
FragmentTab2 {
private interface DataListener {
public Data getData();
}
private DataListener dataListener = new DataListener();
Data = dataListener.getData();
}
FragmentTab1 implements DataListener {
#Override
public Data getData() {
return Data;
}
}
Or a bit more involved should you need to notify, register, and unregister listeners try this here: Observer Design Pattern

Related

Activity/Fragment and ViewModel in Adapter good practice?

Let's assume that we have Activity/Fragment which contains a RecyclerView. Furthermore, it sets an Adapter. For the sake of the example, let's say the Adapter has to have access to Fragment in order to call a method which displays a Snackbar. Moreover, Let's say there are a couple of items in the adapter. I want to delete one and remove it from the database. Therefore I should call ViewModel's methods. I've made a research but I couldn't find any information if referencing a fragment into the Adapter is good or not.
Could you help me and explain? Also for the ViewModel I've found some ideas here.
But what are the best practices?
good Adapter Classes should be STATIC helping developers to keep it separated from Activity/Fragment part
don't save Activity/Fragment reference inside Adapters
ViewModels should belongs to Activities or Fragments
Adapters should execute Activity/Fragment's actions via Callbacks/Listeners or LiveData
Pseudo-code:
public class MainActivity extends Activity {
private interface Listener {
void OnRemoved(#NonNull xxx removedItem);
}
private static final class MyAdapter extends ArrayAdapter<xxx> {
private final Listener mListener;
private MyAdapter(#NonNull final Listener listener) {
super(...);
this.mListener = listener;
}
#Override
public void remove(xxx item) {
super.remove(xxx); //<-- this removes item from Adapter
this.mListener.OnRemoved(item); //<-- this triggers Activity's code
}
}
public void onCreate(...) {
...
new MyAdapter(new Listener() {
#Override
public void OnRemoved(#NonNull final xxx removedItem) {
Snakbar.makeText(....).show();
}
});
}
}

Wait for ListAdapter to complete so I can apply a filter

Right now, I'm getting some values to fill a recyclerView with the following list adapter through binding:
private val otrosSubmitListAdapter = OtrosSubmitListAdapter()
[more code]
binding.otrosRequestList.adapter = otrosSubmitListAdapter
Problem is that I'd like to, when all values have been binded, merge then with some other values, I'd like to make the merge in a variable called DummyContent.ITEMS, which I would later put a new filterAdapter and use that adapter for my recyclerview, like this:
dataArray = DummyContent.ITEMS
filter_adapter = MyFilterAdapter(this.activity, dataArray)
recyclerView.adapter = filter_adapter
Problem is that I cannot grasp a way for waiting so OtrosSubmitListAdapter() has completed all its internal binding and I can get its values properly, right now by using this code DummyContents have never the values needed from OtrosSubmitListAdapter() to be merged, so only its other values can be properly shown.
What would be a possible way to wait for OtrosSubmitListAdapter() to complete all its binding and getting to properly use the results?
Create a callback inside your OtrosSubmitListAdapter like this:
public interface AdapterCallback {
void itemsBound();
}
Add it to your activity
public class MainActivity extends AppCompatActivity implements AdapterCallback
Pass a reference of AdapterCallback to OtrosSubmitListAdapter when you are initializing it
On your adapter
AdapterCallback adapterCallback;
public OtrosSubmitListAdapter(AdapterCallback adapterCallback){
this.adapterCallback = adapterCallback;
}
#Override
public void onBindViewHolder(final OtrosSubmitListAdapter.MyViewHolder holder, final int position) {
if (position == itemList.size() - 1){
adapterCallback.itemsBound();
}
}
On your activity
private val otrosSubmitListAdapter = OtrosSubmitListAdapter(this)
#Override
public void itemsBound() {
//enter code here
}
see https://stackoverflow.com/a/32032990/11881779 for adapter callback example
Edit : If I understood your question wrong, please share code of your adapter and activity

RecyclerView - Access to a list from another class

I want to access a list from another class then put it inside my RecyclerViewAdapter object .
The first class which contains the list.
public class Class1 {
// The List :
List<Model1> mlisto = new ArrayList<>();
mlisto.add(new Model1("HOLA","Dep17",R.drawable.img));
mlisto.add(new Model1("bonjour","Dep17",R.drawable.img));
mlisto.add(new Model1("hi","Dep17",R.drawable.img));
}
The second class which access the list from the first class.
public class Class2 {
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this,new Class1().mlisto);
}
When I use new Class1().mlisto it returns nothing like an empty list
and the RecyclerView doesn't show anything on the app.
you can use interfaces
create an interface inside class1 like this:
public interface CustomListListener{
void onListChanged(List<Model1> myList);
}
create a property of listener inside Class1:
CustomListListener mListener;
add a public function for initializing the listener inside Class1:
public static void setOnListChangeListener(CustomListListener listener){
this.mListener = listener;
}
implement the listener inside Class2:
public class Class2 implements Class1.CustomListListener {
}
when you implement listener inside Class2, you will get a function inside class2 like this :
#Override
public void onListChanged(List<Model1> myList) {
// in here you will access the list that you created or changed inside class1
}
when you wanna send the myList data to class2:
1- initiate the mListener property :
for example you can initiate the mListener inside OnCreate Function of class
Class1.setOnListChangeListener(this)
this refers to class2 context
2- send the data to class2
inside your class1, whenever you want to update the list use mListener property like this :
mListener.onListChanged(myList);
this like you can change the list whenever you want and get the updated value inside onListChanged function, also you can add more functions inside your CustomListListener for different scenarios like removing items, adding items and etc...
You can access the list like this :
public class Class1{
private List<Model> mList;
public List<Model1> getList(){
mList = new ArrayList<>();
mList.add(new Model1("HOLA","Dep17",R.drawable.img));
mList.add(new Model1("bonjour","Dep17",R.drawable.img));
mList.add(new Model1("hi","Dep17",R.drawable.img));
return mList
}
}
And in second class, you can use it like this:-
RecyclerViewAdapterrr adapter = new RecyclerViewAdapterrr(this,new Class1().getList());
setAdapter() is important
your_recyclerview_object.setAdapter(adapter);
You can use sharedPreference to store the list and can access it anywhere in your project by using its key. The best approach is shared in this link TinyDb Example

android: how to make interface between recycler view and adapter clss

I have a recyclerview which has Switch Button on each item and I want to add switch.setOnCheckedChangeListener for items. how can I make an interface between adapter class and the recyclerview host activity??
First you will create an interface class
public interface ExampleInterface {
void udpateData(String data);
}
The interface will be defined with name and parameters that you want
Second in the activity or fragment having RecycleView, you need implement this interface.
Third, when you call the your adapter please pass this interface to your adapter. Each time your Switch Button change status, interface will call updateData method to update data
Good luck
In your host activity write a method to handle switch button changed, say
private void switchButtonChanged()
pass the host activity when you create the adapter, for example
Adapter adapter = new Adapter(getActivity())
under your onCheckedChangedListener() in adapter, fire hostActivity.switchButtonChanged()
There is a simple way to do it. interface.
public class YourAdapter extends YourAdapterExtends {
private AdapterInteractionListener adapterInteractionListener;
... // your adapter codes
public YourAdapter(AdapterInteractionListener adapterInteractionListener){
this.adapterInteractionListener = adapterInteractionListener;
}
//call where you call switch.setOnCheckedChangeListener method
switch. setOnCheckedChangeListener{
adapterInteractionListener.onSwitched;
}
//here your interaction interface.
public interface AdapterInteractionListener{
void onSwitched();
}
}
And your host activity
public class YourActivity extends YourExtends impelements YourAdapter.AdapterInteractionListener {
...//your activity codes
#Override
onSwitched{
//here your switch listener triggered here
}
}
I hope this helps.

Communicating between components in Android

So I have an Activity. The Activity hosts a ViewPager with tabs, each tab holding a Fragment in it. The Fragments themselves have a RecyclerView each. I need to communicate changes from the RecyclerView's adapter to the activity.
Currently, I am using the listener pattern and communicating using interface between each of the components. i.e I have an interface between the RecyclerView's adapter and the Fragment holding it. Then an interface from the Fragment to the ViewPager's FragmentStatePagerAdapter which is creating all the Fragments. And 1 more interface between the ViewPager's adapter and the Activity hosting the ViewPager. I feel that there are too many interfaces for all the components because of how they are structured.
Currently I am not facing issues as such but I think the listener pattern is acting like an anti-pattern due to all the nested components. Instead of creating independent components I think the hierarchy will make it difficult for making code changes in future.
Am I doing it correctly or is there a better way to do it? Is this a case where I should use an Event Bus or Observer Pattern (If yes can you point me to some examples where someone overcame a similar problems using it)?
NOTE : If it matters, I need it to maintain a global object in the activity, something like a shopping cart where I can add or remove items and these items are present in RecyclerView's adapter from where I can add it to the cart and also increment or decrement the count for a particular item. The ViewPager and Tabs help segregate these items in various categories.
Edit 1 : Some code trying out #LucaNicoletti's approach -
I have skipped one level that is the level with the ViewPager's FragmentStatePagerAdapter. I guess that should not matter and stripped of some other code to keep it small.
MainActivity:
public class MainActivity extends AppCompatActivity implements View.OnClickListener, FoodAdapter.OnFoodItemCountChangeListener {
#Override
public void onFoodItemDecreased(FoodItemModel foodItemModel, int count) {
Log.d("Test", "Dec");
}
#Override
public void onFoodItemIncreased(FoodItemModel foodItemModel, int count) {
Log.d("Test", "Inc");
}
// Other methods here
}
Fragment hosting the Adapter:
public class FoodCategoryListFragment extends Fragment implements FoodAdapter.OnFoodItemCountChangeListener {
// Other boring variables like recyclerview and layout managers
FoodAdapter foodAdapter;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Other boring intializations for recyclerview and stuff
// I set the click listener here directly on the adapter instance
// I don't have this adapter instance in my activity
foodAdapter.setOnFoodItemClickListener(this);
rvFoodList.setAdapter(foodAdapter);
}
}
The adapter class at the lowest level:
public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.FoodViewHolder> {
private OnFoodItemCountChangeListener onFoodItemCountChangeListener;
private List<FoodItemModel> foodItems;
// The interface
public interface OnFoodItemCountChangeListener {
void onFoodItemIncreased(FoodItemModel foodItemModel, int count);
void onFoodItemDecreased(FoodItemModel foodItemModel, int count);
}
// This is called from the fragment since I don't have the adapter instance
// in my activty
public void setOnFoodItemClickListener(OnFoodItemCountChangeListener onFoodItemCountChangeListener) {
this.onFoodItemCountChangeListener = onFoodItemCountChangeListener;
}
// Other boring adapter stuff here
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bMinus:
onFoodItemCountChangeListener.onFoodItemDecreased(foodItems.get(getAdapterPosition()),
Integer.parseInt(etCounter.getText().toString()));
}
break;
case R.id.bPlus:
onFoodItemCountChangeListener.onFoodItemIncreased(foodItems.get(getAdapterPosition()),
Integer.parseInt(etCounter.getText().toString()));
}
break;
}
}
}
my comments were:
what you should/could do it's to have a global data repo which holds the shopping cart and listeners associated with changes to it. Like a singleton, like ShoppingCart.getInstance().addListener(this); and ShoppingCart.getInstance().addItem(new Item(id));
and
Yes. That's what I'm suggesting. Do not forget that this Singleton can never ever holds Context or Activity because u don't want to leak memory, so always call removeListener. On my opinion it would reduce dependency as all your view controllers only interact with the data model
and I'll add some code to exemplify as a proper answer.
Below is a very crude, typed by heart code, but it should give an idea. All the UI elements are only tied to the data, and not to each other.
Similar stuff could be implemented with libraries that provide observable pattern out of the box for data-only objects.
public class ShoppingCart {
private ShoppingCart single;
private static void init(){
.. init single if not null
}
private List<Item> items = new ArrayList<>();
public int numberOfItems;
public long totalPrice;
private static void addItem(Item item){
init()
single.items.add(item);
single.numberOfItems++;
single.totalPrice+=item.price;
dispatchChange();
}
private static void removeItem(Item item){
init();
single.numberOfItems--;
single.totalPrice-=item.price;
dispatchChange();
single.items.remove(item);
}
private void dispatchChange(){
// TODO: write real loop here
for(single.listeners) listener.onCartChanged(single.cart);
}
public interface Listener {
void onCartChanged(ShoppingCart cart);
}
private List<Listener> listeners = new ArrayList<>();
// TODO: addListener and removeListener code
public static class Item {
String id;
String name;
long price;
}
}
To communicate between components (Activity, Fragment) you have to use an event bus.
In android, you could choose between:
RxJava
Otto
Green Robot EventBus
A blog to explain this.

Categories

Resources