I have an custom adapter that is giving me problem. When I add or edit something it updates the listview but when I delete it doesn't.
Code when I remove something:
private ArrayList<Teams> m_orders = null;
private TeamsAdapter m_adapter;
private ListView lstv;
...
private void deleteTeam(int indexRemove){
hasKeys.remove(hasKeys.indexOf(m_orders.get(indexRemove).getTeamName()));
Menu.teams.remove(m_orders.get(indexRemove).getTeamName());
m_orders.remove(indexRemove);
m_adapter.notifyDataSetChanged();
}
I tried use a Runnable, but without success.
private Runnable returnRes = new Runnable() {
#Override
public void run() {
if(m_orders != null && m_orders.size() > 0){
m_adapter.notifyDataSetChanged();
for(int i=0;i<m_orders.size();i++)
m_adapter.add(m_orders.get(i));
}
m_adapter.notifyDataSetChanged();
}
};
My onCreate method:
lstv = findViewById(R.id.teamsList);
m_orders = new ArrayList<Teams>();
this.m_adapter = new TeamsAdapter(this, R.layout.row, m_orders);
lstv.setAdapter(this.m_adapter);
You have to remove an item from the ArrayList which is inside the Adapter class. So you need to write your delete function inside the adapter class. In this way will able to delete items and update listview by calling notifyDataSetChanged() method.
You are creating an m_adapter with m_orders dataset, but you are removing item from m_teams dataset, make no sense, they are different instances.
final List<Teams> mTeams = new ArrayList<>();
TeamsAdapter mAdapter;
onCreate() {
mAdapter = new TeamsAdapter(this, R.layout.row, mTeams);
ListView listView = (ListView) findViewById(R.id.teamsList);
listView.setAdapter(mAdapter);
}
addTeams(Collection<Teams> items) {
mTeams.addAll(items);
mAdapter.notifyDataSetChanged();
}
deleteTeam(int index) {
mTeams.remove(index);
mAdapter.notifyDataSetChanged();
}
Related
I have this on my GroupDescriptionActivity class:
GroupDescriptionViewModel mFavViewModel;
ArrayList<String> mFav;
mFavViewModel = new ViewModelProvider(this).get(GroupDescriptionViewModel.class);
final Observer<ArrayList<String>> favsObserver = new Observer<ArrayList<String>>() {
#Override
public void onChanged(#Nullable final ArrayList<String> updatedList) {
if (mFav == null) {
mFav = updatedList;
ArrayAdapter arrayAdapter = new ArrayAdapter(context, android.R.layout.simple_expandable_list_item_1, mFav);
partecipants.setAdapter(arrayAdapter);
}
}
};
And in my GroupDescriptionViewModel:
public class GroupDescriptionViewModel extends AndroidViewModel {
private static MutableLiveData<ArrayList<String>> mFavs;
public GroupDescriptionViewModel(#NonNull Application application) {
super(application);
}
public static MutableLiveData<ArrayList<String>> getFavs(ArrayList<HashMap> partecipants) {
if (mFavs == null) {
mFavs = new MutableLiveData<>();
}
loadFavs(partecipants);
return mFavs;
}
public static void loadFavs(ArrayList<HashMap> partecipants) {
ArrayList<String> newFavs = new ArrayList<>();
for (HashMap member : partecipants) {
newFavs.add(member.get("mail").toString());
}
mFavs.setValue(newFavs);
}
}
I then have a firestore database change listener in the Source.java file. How can I update my ListView which is in the activity GroupDescription from Source.java?
I tried in Source.java
GroupDescriptionViewModel.getFavs((ArrayList<HashMap>) ((HashMap) arr.get(2)).get("partecipants"));
but didn't work. ((ArrayList<HashMap>) ((HashMap) arr.get(2)).get("partecipants") is my new array for the updates.
So I would like the new data to be entered from source via livedata, and my listview to update in real time
if Source.Java has a listener, why not implement it in the activity GroupDescription? or make an instance of Source.java in your viewModel and set the listener interface there and postValue of your MutableLiveData() inside the listener interface and observe it in your activity? from there you can notify your recyclerView adapter.
I am learning RecyclerView in MVVM pattern from a youtube video. I create a recycler view to load very simple items. It works fine, but when I navigate to a new activity and then come back to the activity using Recycler View. My items in the list is duplicated. For example, my recycler view shows 2 items like Item1 and Item2. After I move to a new activity and return back, the list become Item1, Item 2, Item1 and Item2. So, each time I move to the new activity and return back, it keep doubling more and more. I only want the recycler view load one time, how can I solve this problem? Thank you.
My repo:
public class DWCategoryRepository {
private static DWCategoryRepository instance;
private ArrayList<DWCategories> dataSet = new ArrayList<>();
public static DWCategoryRepository getInstance() {
if (instance == null){
instance = new DWCategoryRepository();
}
return instance;
}
public MutableLiveData<List<DWCategories>> getDWCategories(){
setDWCategories();
MutableLiveData<List<DWCategories>> data = new MutableLiveData<>();
data.setValue(dataSet);
return data;
}
private void setDWCategories() {
dataSet.add(new DWCategories("Item1"));
dataSet.add(new DWCategories("Item2"));
}
}
My ViewModel:
public class MainWalletViewModel extends ViewModel {
private MutableLiveData<List<DWCategories>> mCategories;
private DWCategoryRepository mRepo;
public void init(){
if (mCategories != null) {
return;
}
mRepo = DWCategoryRepository.getInstance();
mCategories = mRepo.getDWCategories();
}
public LiveData<List<DWCategories>> getDWCategories(){
return mCategories;
}
}
View:
public class MainWalletActivity extends DWBaseActivity implements WalletCategoryAdapter.OnCategoryListener {
private WalletCategoryAdapter mWalletCategoryAdapter;
private MainWalletViewModel mMainWalletViewModel;
private RecyclerView mRecyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initializeDataBinding();
}
private void initializeDataBinding() {
MainWalletActivityBinding dataBinding = DataBindingUtil.setContentView(this, R.layout.main_wallet_activity);
setSupportActionBar(dataBinding.walletToolbar);
//Enable Back button on Toolbar
showBackArrowOnToolbar();
//Get Categories from View Model
initCategories();
//Set up adapter
mWalletCategoryAdapter = new WalletCategoryAdapter(this, mMainWalletViewModel.getDWCategories().getValue(), this);
//Set adapter to Recycler view
mRecyclerView = dataBinding.walletCategoryRV;
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mWalletCategoryAdapter);
//Add divider to Recycler view
mRecyclerView.addItemDecoration(new DividerItemDecoration(MainWalletActivity.this,
DividerItemDecoration.VERTICAL));
}
private void initCategories(){
mMainWalletViewModel = ViewModelProviders.of(this).get(MainWalletViewModel.class);
mMainWalletViewModel.init();
mMainWalletViewModel.getDWCategories().observe(this, new Observer<List<DWCategories>>() {
#Override
public void onChanged(#Nullable List<DWCategories> dwCategories) {
mWalletCategoryAdapter.notifyDataSetChanged();
}
});
}
}
You are calling setDWCategories in your getter.
public MutableLiveData<List<DWCategories>> getDWCategories(){
setDWCategories(); // <- Remove this line!
MutableLiveData<List<DWCategories>> data = new MutableLiveData<>();
data.setValue(dataSet);
return data;
}
You should only initialize your repo data once. Maybe do it in your getInstance() method if you are ok, starting over every time you run the app.
I am creating an arraylist from my database in android for use in adapter of recycler view:
RecyclerView recyclerView = (RecyclerView) getView().findViewById(R.id.homeRecycler);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
ArrayList<StocksforHome> stockList = new ArrayList<>();
DbInteract interact = new DbInteract(getContext());
Cursor cursor = interact.readtable();
HomeFragmentAdapter homeFragmentAdapter = new HomeFragmentAdapter(stockList, getContext());
GetHomeData getHomeData = new GetHomeData(getContext(),homeFragmentAdapter);
int i=0;
stockList.clear();
while(cursor.moveToNext())
{
StocksforHome temp = new StocksforHome();
temp.stock = cursor.getString(cursor.getColumnIndex(eventDBcontract.ListofItem.columnsym));
stockList.add(temp);
}
homeFragmentAdapter.addall(stockList);
Log.d(tag,String.valueOf(stockList.size()) + " " + String.valueOf(cursor.getCount()));
recyclerView.setAdapter(homeFragmentAdapter);
There is only one data in database but still the size of arraylist is 2. I checked that the extra data is duplicate of first one.
Log report:
D/HomeFragment: 2 1
I have made a custom adapter. Its addall method is:
public void addall(ArrayList<StocksforHome> more)
{
stockArrayList.addAll(more);
notifyDataSetChanged();
}
Any idea why this is happening and how to solve it?
That's because stockList in adapter and stockList in code snippet are the same reference, in result items are added twice. To fix this adapter needs his own instance of List.
First add:
stockList.add(temp);
Second add:
homeFragmentAdapter.addall(stockList);
Fix adapter like this:
HomeFragmentAdapter {
private final List<StocksforHome> stockList = new Arraylist<>();
public HomeFragmentAdapter(Context context) {
}
public void addall(List<StocksforHome> more) {
stockList.clear();
stockList.addAll(more);
notifyDataSetChanged();
}
}
Try this .
RecyclerView recyclerView = (RecyclerView) getView().findViewById(R.id.homeRecycler);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
ArrayList<StocksforHome> stockList = new ArrayList<>();
DbInteract interact = new DbInteract(getContext());
Cursor cursor = interact.readtable();
HomeFragmentAdapter homeFragmentAdapter;
GetHomeData getHomeData = new GetHomeData(getContext(), homeFragmentAdapter);
int i = 0;
// clear and add data in your code
stockList.clear();
while (cursor.moveToNext()) {
StocksforHome temp = new StocksforHome();
temp.stock = cursor.getString(cursor.getColumnIndex(eventDBcontract.ListofItem.columnsym));
stockList.add(temp);
}
if (homeFragmentAdapter == null) {
homeFragmentAdapter = new HomeFragmentAdapter(stockList, getContext());
Log.d(tag, String.valueOf(stockList.size()) + " " + String.valueOf(cursor.getCount()));
recyclerView.setAdapter(homeFragmentAdapter);
} else {
// add all data
homeFragmentAdapter.addall(stockList);
}
Firstly , getting data
Secondly , setting it to the adapter
homeFragmentAdapter = new HomeFragmentAdapter(stockList, getContext());
And refresh data in your code
homeFragmentAdapter.addall(stockList);
I have two classes , the first one is for the GUI , where I declared my listview and the adapter , and the setters , to call them from my second class .
public class AndroidGUIModifier implements IMyComponentGUIModifier, IFragmentEvents {
private transient ListView lv;
List<String> mydeviceslist;
ArrayAdapter<String> adapter ;
public void setAdapter(ArrayAdapter<String> adapter) {
this.adapter = adapter;
adapter.notifyDataSetChanged();
}
public void setMydeviceslist(List<String> mydeviceslist) {
this.mydeviceslist = mydeviceslist;
}
#Override
public void onCreateView() {
lv=(ListView) fragment.findViewById("xdevices") ;
mydeviceslist = new ArrayList<String>();
adapter = new ArrayAdapter<String>(fragment.getContext(),android.R.layout.simple_list_item_1,mydeviceslist);
lv.setAdapter(adapter);
In my second class I'll wait an event to receive the list that I want to load it in my listview , then I'll call the list setter to set the new received list and the adapter setter to update it , but it didn't work , nothing was displayed despite I receieved the list of devices in my log .
public class triprincipal extends BCModel {
public List<String> mydevices ;
BCEvent bcEvent;
final ArrayAdapter<String> adapter =guiModifier.getAdapter();
while (isRunning()) {
bcEvent = waitForBCEvent();
if (bcEvent.getID() == checkevent) {
mydevices = bcCommandSenderPlugin.getDevicesNames(); // here I get a list of my devices
Log.i("devices", mydevices.toString());
guiModifier.getFragment().getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
guiModifier.setMydeviceslist(mydevices);
guiModifier.setAdapter(adapter);
}
} );
In setMydeviceslist() do it like:
this.mydeviceslist.addAll(mydeviceslist);
adapter.notifyDataSetChanged();
Hope it will help you out.
adapter.notifyDataSetChanged() will not work in this case, as the value of the reference you have passed to the adapter doesn't actually change.
You will need to create a new Adapter and set it to the ListView to make it work. Change your setAdapter() to this :
public void setAdapter() {
this.adapter = new ArrayAdapter<String>(fragment.getContext(), android.R.layout.simple_list_item_1, mydeviceslist);
lv.setAdapter(adapter);
}
try to update the list in same fragment/activity and after update call notifyDataSetChanged() both in same activity/fragment ....donot set adapter on list repetedly......hope it helps
I have an activity Mainactivity, in this when a button is pressed then it will show a listview. But in
listAdapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1, android.R.id.text1, value);
I am getting "Cannot resolve constructor ArrayAdapter (anonymous android view.View.OnClickListener, int, int, java.lang.String)"
My outer class is "Mainactivity" I tried "Mainactivity.this" instead of "this". But It is showing "cannot resolve constructor" error.
MainActivity class extends Actionbaractivity implements onItemelectedListner
My code is:
ok.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(cnt.getText().toString().length() > 0 &&
number.getText().toString().length() > 0 &&
Integer.parseInt(number.getText().toString()) > 0 &&
Integer.parseInt(cnt.getText().toString()) > 0) {
number.requestFocus();
String[] value = new String{"hello","world"};
try {
temp_count = temp_count + Integer.parseInt(cnt.getText().toString());
count.setText(String.valueOf(temp_count));
temp_amt = temp_amt + (Integer.parseInt(cnt.getText().toString()) * tkt_rate);
amount.setText(String.valueOf(temp_amt));
ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1, value);
lstView.setAdapter(listAdapter);
lstView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
SparseBooleanArray checked = lstView.getCheckedItemPositions();
int size = checked.size(); // number of name-value pairs in the array
for (int i = 0; i < size; i++) {
int key = checked.keyAt(i);
boolean value = checked.get(key);
if (value) {
row = lstView.getChildAt(i);
row.setBackgroundColor(Color.parseColor("#33B5E5"));
} else {
row = lstView.getChildAt(i);
row.setBackgroundColor(Color.parseColor("#F0F0F0"));
}
}
}
});
Please help...
The error shows that you are putting android view.View.OnClickListener as the first argument.
I know you said you have tried, but you really need to use Mainactivity.this. If it is not working please post the code of the start of your java file.
Also is your activity named as Mainactivity? Remember it is case sensitive, should it be MainActivity? If so, you have to use MainActivity.this
I think it's happening because your class implements onclicklistener. So can you try cast this to Activity? Like the code below:
listAdapter = new ArrayAdapter((Activity)this, android.R.layout.simple_list_item_1, android.R.id.text1, value);
ArrayAdapter needs Context as the first argument. What you can do is to have a field reference to your Context, like the followings.
Added a field to your Activity, private Context mContext;
Inside the onCreate() of your Activity, mContext = this;
Use the mContext to construct ArrayAdapter, listAdapter = new ArrayAdapter(mContext, android.R.layout.simple_list_item_1, android.R.id.text1, value);
Maybe this will help you:
listAdapter = new ArrayAdapter(MainActivity.this,
android.R.layout.simple_list_item_1,
android.R.id.text1,
Collections.singletonList(value));