Framents in viewpager displaying the same content - android

I have pondered on this for days now, I need help. I have 2 fragments in a viewpager. They are both showing the same values despite feeding them with different data.
Link to image
Fragment A has a spinner dropdown of countries same as Fragment B. Fragment A is supposed to show list of Hospitals when country is selected, Fragment B is supposed to show list of Schools depending on country selected.
PROBLEM
When I select a country in Fragment A, I get the list of hospitals in fragment A. When I swipe to fragment B, I find the list of hospitals which are supposed to be in A displayed. When I select a country in B, the list refreshes and I get the list of schools as should be, but when I swipe back again to fragment A I find the same list of schools instead of list of hospitals previously selected. I am using dagger2 with databinding.
Below code depicts one scenario but they are basically the same just different adapters and also different layouts.
CODE
private void initRecyclerview() {
binding.rvSchools.setHasFixedSize(true);
adapter = new SchoolsAdapter(getContext());
binding.rvSchools.setLayoutManager(new LinearLayoutManager(getContext()));
binding.rvSchools.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
private void countries() {
viewModel.getCountries().removeObservers(getViewLifecycleOwner());
viewModel.getCountries().observe(getViewLifecycleOwner(), new Observer<Resource<List<Countries>>>() {
#Override
public void onChanged(Resource<List<Countries>> countriesList) {
switch (countriesList.status) {
case SUCCESS:
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<>(getApplicationContext,
R.layout.simple_spinner_item, countriesList);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
binding.spinner.setAdapter(spinnerAdapter);
spinnerAdapter.notifyDataSetChanged();
break;
}
}
});
binding.spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String country = countriesList.get(position);
schools(country);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {}
});
}
private void schools(String country) {
viewModel.getSchoolsHospitals(country, "School").removeObservers(getViewLifecycleOwner());
viewModel.getSchoolsHospitals(country, "School").observe(getViewLifecycleOwner(), new Observer<Resource<List<SchoolsHospitals>>>() {
#Override
public void onChanged(Resource<List<SchoolsHospitals>> schoolsList) {
switch (schoolsList.status) {
case SUCCESS:
binding.setSchools(schoolsList.data);
}
}
});
}

This is a rather odd behaviour considering how I wanted to re-use code. I was using the same viewModel class because the data is the same. After creating a separate viewModel class for Schools i.e a duplicate ViewModel just different class names, the respective contents were set as needed.
If there is a better approach, it will be much appreciated.

Related

Spinner Array needs to link it's items to existing layouts?

So the spinner I have currently picks from a programmatic array which fetches names and images based on what's in the array.
What I need is to only pick from items in the array if they exist based on the layouts I have.
eg. I have multiple accounts in my main activity list. I only want to be able to pick an account in my spinner based on the accounts I have available (user only has 2 of 3 accounts from the array, thus only display 2 items in the spinner not all 3)
Here's my current spinner code as well as the array:
SpinnerActivity:
public class SpinnerActivity extends AppCompatActivity {
private ArrayList<AccountItem> mAccountList;
private AccountAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_transactions);
//the account_spinner is being pulled from the fragment_transactions xml
initList();
Spinner spinnerAccount = findViewById(R.id.account_spinner);
mAdapter = new AccountAdapter(this, mAccountList);
spinnerAccount.setAdapter(mAdapter);
spinnerAccount.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
AccountItem clickedItem = (AccountItem) parent.getItemAtPosition(position);
String clickedAccountName = clickedItem.getAccountName();
Toast.makeText(SpinnerActivity.this, clickedAccountName + " selected", Toast.LENGTH_SHORT).show();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
/**
*This is the array, I need this to link each item to their respective accounts
*that are available
**/
private void initList() {
mAccountList = new ArrayList<>();
mAccountList.add(new AccountItem("Account1", R.drawable.account1_icon));
mAccountList.add(new AccountItem("Account2", R.drawable.account2_icon));
mAccountList.add(new AccountItem("Account3", R.drawable.account3_icon));
}
}
I just need an idea of where to start. As it stands I don't see a way to give my array items individual IDs so I'm not sure if I need to change my array?
You just change the array. If you need to fetch the account list asynchronously, you can call mAdapter.notifyDataSetChanged() in the async completion callback to tell the Adapter that its backing array has changed.

Android Problems

I have a problem that i am trying to solve using android to develop and app for a trivia quiz so i need to start a quiz based on the category chosen. The problem is as follows:
Question 1
I cant seem to figure out how to pass the item selected from a ListView i can pass what is selected using spinner but not a list selection.
private String getCategory(){
final String category[] =new String[1];
final ListView list = (ListView) findViewById(R.id.soloList);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> myAdapter, View View, int position, long id) {
category[0] =(String) (list.getItemAtPosition(position));
}
});
return category[0];
}
That is the part of the code is use and cant seem to get it to work and my question is how do i make it work? I call the method within main but nothing ever gets passed.
Thanks.
About Q1 :
You have function that return String it's ok but what's wrong that not made code work is ItemClickListener
First let me tell you about Interfaces in Java :
As you've already learned, objects define their interaction with the outside world through the methods that they expose. Methods form the object's interface with the outside world; the buttons on the front of your television set, for example, are the interface between you and the electrical wiring on the other side of its plastic casing. You press the "power" button to turn the television on and off. - link
The problem in this code is that you set kind of interface on each item click, but you function not wait for item click callback to return result !
the way you can handle is :
1: Create Interface for Callback when user select new item on listview
public interface category {
public void getCategory(String itemTitle);
}
2: set callback to you Activity Fragment or ...
public class ProjectList extends Fragment implements category
3: Override callback function
#Override
public void getCategory(String itemTitle) {
// do something with new item !
}
4: Call callback function when item selected
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> myAdapter, View View, int position, long id) {
ProjectList.this.getCategory("newitem-String")
}
});

How to update RecyclerView's data dynamiclly?

I have some tables in the database, every table has many rows,I want to show the tables's data in a list, so I use a RecyclerView to show the data, and a spinner to select the table which I want to show.
But now, when I select an item of spinner, the RecyclerView doesn't have any changes ,it can't show the new data only after I reopen the fragment.
My code:
In adapter:
1.removeItem works
the item in the RecyclerView will be removed when removeItem called.
public void removeItem(WordCls wordCls) {
int position = wordsList.indexOf(wordCls);
wordsList.remove(position);
notifyItemRemoved(position);
}
2.updateList doesn't work
But when updateList called,nothing happened in the view
public void updateList(List<WordCls> wordsList) {
//this.wordsList = wordsList;
this.wordsList.clear();
this.wordsList.addAll(wordsList);
notifyDataSetChanged();
}
In fragment:
in onCreateView():
recyclerView = (RecyclerView) view.findViewById(R.id.wordbook_recycler_list);
recyclerView.setLayoutManager(new LinearLayoutManager(activity));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setHasFixedSize(true);
wordsList = WordsManager.getWordsList(tableName);
wordCardAdapter = new WordCardAdapter(activity, tableName, wordsList);
recyclerView.setAdapter(wordCardAdapter);
wordCardAdapter.setOnItemClickListener(new WordCardAdapter.OnRecyclerViewItemClickListener() {
#Override
public void onItemClick(View view, WordCls wordCls) {
Toast.makeText(getActivity(), wordCls.getWord(), Toast.LENGTH_SHORT).show();
wordCardAdapter.removeItem(wordCls);
WordsManager.deleteWord(tableName, wordCls.getWord());
}
});
in SpinnerItemSelectedListener:
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position,long id) {
tableName= parent.getItemAtPosition(position).toString();
prefEditorSettings.putInt(KEY_SPINNER_SELECTED_ITEM, position);
prefEditorSettings.commit();
tableName = getWordbookList().get(spnSelectedPosition);
wordsList = WordsManager.getWordsList(tableName);
wordCardAdapter.updateList(wordsList);
Toast.makeText(activity, tableName, 2000).show();
}
==============================================
update:
the method updateList is right.
just my careless to have passed a wrong param at
tableName = getWordbookList().get(spnSelectedPosition);
it should be
tableName = getWordbookList().get(position);
now, it works.
Actually, I don't know if RecyclerView is the best way to fulfill your purpose.
RecyclerView(s) are to be used when you have to show multiple instances of your List, in a list-y way :)
If you have just one View to update (that contains multiple fields to be updated), I'd choose some data-binding library like RoboBinding or the new beta version of google binding library (MVVM paradigm)
I'm not going into further details as I just want to warn you about MVVM programming paradigm that can be a worthy solution in your case.
instead of wordCardAdapter.updateList(wordsList) , add new data to wordsList and wordCardAdapter.notifyDataSetChanged() inside spinner
hope it works.

Filtering list view and getting correct onclick item

I have a list view and I've implemente filtering.
Lets say I have items A, B and C. If I type B in the filter box, only item B will be displayed and it is the position 0 of the list (before it was in position 1). So when I call the onClick item, I get the the id/position 0, which leads to displaying details about A instead of B.
This is the onclick code:
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Poi poi = pois.get((int)id);
goPOIDETAIL(poi);
}
});
id and position have the same value.
is there a way to get the original position, or get some other value indicating the real item that I clicked?
Thanks
flashsearchList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Integer temp=flashSearchNameMap.get(adapter.getItem(position));
navigateSearch(temp);
}
});
(adapter.getItem(position) will return you the exact list name and in flashSearchNameMap i have stored names and position at beginning from oncreate before applying filtering.So you can get exact position by this
I think the problem is in the way you manage your filter. You should get the object with selected id not from the original List (or array) but from the filtered one.
I used something like it in this post from my blog. Hope this help you
ID and Index are not the same. Of course, you can return item index in getItemId() method of your adapter, but don't expect your items to be identified correctly by this method if you do.
Try providing unique ID for each of your items. The idea is somewhat similar to ID of each record in the database, which never changes (and lets you reliably identify each record), and it is easily implemented when you get your data from database.
But if your items don't have unique IDs, and you don't want to bother providing them, there's another approach (see this example code for Adapter below):
public MyAdapter extends BaseAdapter {
private List<Item> items;
private List<Item> displayedItems;
public MyAdapter(List<Item> items) {
this.items=items;
this.displayedItems=items;
}
public filter(String query) {
if(query.isEmpty()) {
displayedItems=items;
} else {
displayedItems=new ArrayList<Item>();
for (Item item : items) {
displayedItems.add(...) //add items matching your query
}
}
notifyDataSetChanged();
}
//...
//NOTE: we use displayedItems in getSize(), getView() and other callbacks
}
You can try:
#Override
public boolean hasStableIds() {
return false;
}
in your adapter
if you are using datbase you have the _id key that you can load in a filtered list as invisible field. Once you click on the item you can query data with _id key.
If you aren't using a database you could add a hidden id element in your row element as well.

ArrayAdapter and ListView display only specific items

I am trying to impement a school planner app. There is a timetable overview implemented as a ListView for each day wrapped into a Tab Layout. So the user can switch between days Monday to Friday and gets his timetable for the specific day.
public class TimetableAdapter extends ArrayAdapter<Lesson> {
private List<Lesson> lessonList; // The model
...
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
...
view = inflater.inflate(R.layout.timetable_row, null);
Lesson currentLesson = lessonList.get(position);
// Checks if selected Tab (context.getDay()) correspondends to
// currentLesson's day. If so the lesson will be rendered into
// the appropriated ListView. So if the user selects the Monday Tab
// he only wants to see the lessons for Monday.
if (context.getDay() == currentLesson.getWeekDay().getWeekDay()) {
fillView(currentLesson, holder); // render Lesson
}
...
return view;
}
private void fillView(Lesson currentLesson, ViewHolder holder) {
holder.subject.setText(currentLesson.getSubject().getName());
}
public class TimetableActivity extends Activity implements OnTabChangeListener {
public void onCreate(Bundle savedInstanceState) {
....
timetableAdapter = new TimetableAdapter(this, getModel());
}
private List<Lesson> getModel() {
return timetable.getLessons();
}
public void onTabChanged(String tabId) {
currentTabName = tabId;
if (tabId.equals("tabMonday")) {
setCurrentListView(mondayListView);
}
else if (tabId.equals("tabTuesday")) {
// Checks tabTuesday and so on....
...
}
}
private void addLesson() {
timetable.addLesson(new Lesson(blabla(name, weekday etc.))); // blabla = user specified values
timetableAdapter.notifyDataSetChanged();
}
So basically if the user adds a lesson he specifies some parameters like corresponding weekday, name etc. This is represented by blabla.
The problem is that, because I am using only one ArrayList for my data, wether it's a subject on Monday or on Tuesday the lesson e.g. for Monday is rendered on my Tuesday's ListView as an empty row, because getView(...) is called for each item in lessonList and it just returns a new View(), if the weekday isn't the desired one, I think.
One solution might be creating 5 ArrayLists and 5 ArrayAdapters for the appropriated weekdays. So the lessons on Monday will be in ArrayList mondayList, and the adapter will be bound to this list. But this is somewhat unflexible.
Is there a better solution?
Thanks in advance.
Instead of using ArrayAdapter, use SimpleAdapter. It is far more flexible for what you want to display. Second keep your ArrayList of all the appointments out of the Adapter, create some sort of filtering method to copy applicable objects and pass this new list to the SimpleAdapter.

Categories

Resources