I created ActionMode.Callback method to inflate the ActionBar. I succeeded in inflating the ActionBar but my problem with clicking on the delete item on the ActionBar.
I do not know how to get the position of RecyclerView Item so I can delete it from SQLite Database.
Here my code.
public class ViewList extends AppCompatActivity {
FloatingActionButton fab, fabDel;
RecyclerView rv;
DatabaseHelper dbh;
ArrayList<Data> myValues = new ArrayList<>();
DataAdapter dataAdapter;
ActionMode mActionMode;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().requestFeature(Window.FEATURE_ACTION_MODE_OVERLAY);
setContentView(R.layout.view_list);
dbh = new DatabaseHelper(this);
rv = findViewById(R.id.rv);
fab = findViewById(R.id.fab);
fabDel = findViewById(R.id.fab_del);
Cursor data = dbh.getListContents();
if (data.getCount() != 0) {
while (data.moveToNext()) {
String str1 = data.getString(1);
String str2 = data.getString(2);
Data d = new Data(str1, str2);
myValues.add(d);
dataAdapter = new DataAdapter(myValues);
rv.setAdapter(dataAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rv.setLayoutManager(layoutManager);
}
}else {
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent activityMain = new Intent(getApplicationContext(), MainActivity.class);
startActivity(activityMain);
}
});
return;
}
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent mainactivity = new Intent(getApplicationContext(), MainActivity.class);
startActivity(mainactivity);
}
});
dataAdapter.setOnItemClickListener(new RecyclerViewItemClickListener() {
#Override
public boolean onItemLongClick(View view, int position) {
if (mActionMode != null) {
return false;
}
mActionMode = startSupportActionMode(mActionModeCallback);
return true;
}
});
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
dbh.delete();
myValues.remove();
dataAdapter.notifyDataSetChanged();
mode.finish();
return true;
case R.id.edit:
Toast.makeText(ViewList.this, "Edited", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
}
Adapter Class
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder>{
private ArrayList<Data> myValues;
private RecyclerViewItemClickListener recyclerViewItemClickListener;
private Context context;
private DatabaseHelper dbh;
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tv_title, tv_des;
public int position = 0;
public ViewHolder(final View itemView) {
super(itemView);
tv_title = itemView.findViewById(R.id.tv_title);
tv_des = itemView.findViewById(R.id.tv_des);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
recyclerViewItemClickListener.onItemLongClick(v,position);
return true;
}
});
}
}
public void setOnItemClickListener (RecyclerViewItemClickListener recyclerViewItemClickListener) {
this.recyclerViewItemClickListener = recyclerViewItemClickListener;
}
public DataAdapter(ArrayList<Data> myValues) {
this.myValues = myValues;
dbh = new DatabaseHelper(context);
}
#NonNull
#Override
public DataAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull DataAdapter.ViewHolder holder, final int position) {
holder.tv_title.setText(myValues.get(position).getTitle());
holder.tv_des.setText(myValues.get(position).getDescription());
long id = myValues.get(position).getId();
holder.itemView.setTag(id);
holder.position = position;
}
#Override
public int getItemCount() {
return myValues.size();
}
}
My Model Class
public class Data {
private String title, description;
private long id;
public Data() {
}
public Data(String title, String description) {
this.title = title;
this.description = description;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
DatabaseHelper Class
public class DatabaseHelper extends SQLiteOpenHelper{
public static final String DATABASE_NAME = "mylist.db";
public static final String TABLE_NAME = "mylist_data";
public static final String COL1 = "id";
public static final String COL2 = "ITEM1";
public static final String COL3 = "ITEM2";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE " + TABLE_NAME + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
"ITEM1 TEXT, ITEM2 TEXT)";
db.execSQL(createTable);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
}
public boolean addData(String item1, String item2) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COL2, item1);
contentValues.put(COL3, item2);
long result = db.insert(TABLE_NAME, null, contentValues);
if (result == -1) {
return false;
}else {
return true;
}
}
public Cursor getListContents() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor data = db.rawQuery("SELECT * FROM " + TABLE_NAME, null);
return data;
}
public void delete(long id) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, "id = ?", new String[]{String.valueOf(id)});
}
}
Some fact exist that you have to pay attention.
Setting click listener in ViewHolder is not correct, since RecyclerView cache by default viewholders it creates. So the position is not always retrieved correctly in your code. In this regard i make some changes to access the position, and flee from this situation.
Change you Viewholder class as following and remove click listener from it:
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tv_title, tv_des;
public int position = 0;
public ViewHolder(final View itemView) {
super(itemView);
tv_title = itemView.findViewById(R.id.tv_title);
tv_des = itemView.findViewById(R.id.tv_des);
}
}
Then change on bindViewHolder like following code snippet and assign the listener there:
#Override
public void onBindViewHolder(#NonNull DataAdapter.ViewHolder holder, final int position) {
holder.tv_title.setText(myValues.get(position).getTitle());
holder.tv_des.setText(myValues.get(position).getDescription());
long id = myValues.get(position).getId();
holder.itemView.setTag(id);
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
recyclerViewItemClickListener.onItemLongClick(v,position);
return true;
}
});
}
now you have access to position correctly.
EDIT:
Since RecyclerView cache ViewHolders, then it would reuse view holder object for multiple rows which are not visible. So some properties like position would be overridden. but onbindViewHolder will be invoked every time a new row is attaching to visible part of screen, with correct position. So I removed listener from ViewHolder and put in onViewHolderBind.
pay attention to following example:
assume that you have 4 row of data and only 3 of them are visible. In start time since only 3 rows will become visible, recycler view create 3 view holder objects, and assign them to ui, if cache of RecyclerView is active and is active by default, when you scroll upward to see 4th row, recyclerview to manage memory will use viewholder object which become created for first row which is going to be invisible.
Is it clear? or you need some extra explanation? don't hesitate if you need more.
try this Hope it help
public class ViewList extends AppCompatActivity {
FloatingActionButton fab, fabDel;
RecyclerView rv;
DatabaseHelper dbh;
ArrayList<Data> myValues = new ArrayList<>();
DataAdapter dataAdapter;
ActionMode mActionMode;
int pos;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().requestFeature(Window.FEATURE_ACTION_MODE_OVERLAY);
setContentView(R.layout.view_list);
dbh = new DatabaseHelper(this);
rv = findViewById(R.id.rv);
fab = findViewById(R.id.fab);
fabDel = findViewById(R.id.fab_del);
Cursor data = dbh.getListContents();
if (data.getCount() != 0) {
while (data.moveToNext()) {
String str1 = data.getString(1);
String str2 = data.getString(2);
Data d = new Data(str1, str2);
myValues.add(d);
dataAdapter = new DataAdapter(myValues);
rv.setAdapter(dataAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rv.setLayoutManager(layoutManager);
}
}else {
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent activityMain = new Intent(getApplicationContext(), MainActivity.class);
startActivity(activityMain);
}
});
return;
}
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent mainactivity = new Intent(getApplicationContext(), MainActivity.class);
startActivity(mainactivity);
}
});
dataAdapter.setOnItemClickListener(new RecyclerViewItemClickListener() {
#Override
public boolean onItemLongClick(View view, int position) {
pos = position;
if (mActionMode != null) {
return false;
}
mActionMode = startSupportActionMode(mActionModeCallback);
return true;
}
});
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
dbh.delete(arraylist.get(pos).getId);// what ever your getter setter name is
myValues.remove(pos);
dataAdapter.notifyDataSetChanged();
mode.finish();
return true;
case R.id.edit:
Toast.makeText(ViewList.this, "Edited", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
Declare the variable globally
int pos;
Pass the position to this variable like this
dataAdapter.setOnItemClickListener(new RecyclerViewItemClickListener() {
#Override
public boolean onItemLongClick(View view, int position) {
pos = position;
if (mActionMode != null) {
return false;
}
mActionMode = startSupportActionMode(mActionModeCallback);
return true;
}
});
And Use that variable to Delete like this:
case R.id.delete:
dbh.delete(myValues.get(pos).getId);// what ever your getter setter name is
myValues.remove(pos);
dataAdapter.notifyDataSetChanged();
mode.finish();
return true;
Add the id to Model Constructor
public Data(long id,String title, String description) {
this.title = title;
this.description = description;
this.id= id;
}
set the Id :
Cursor data = dbh.getListContents();
if (data.getCount() != 0) {
while (data.moveToNext()) {
String str1 = data.getString(1);
String str2 = data.getString(2);
long id = Long.valueOf(getInt(3))
Data d = new Data(id,str1, str2);
myValues.add(d);
dataAdapter = new DataAdapter(myValues);
rv.setAdapter(dataAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rv.setLayoutManager(layoutManager);
}
make following changes:
dataAdapter.setOnItemClickListener(new RecyclerViewItemClickListener() {
#Override
public boolean onItemLongClick(View view, int position) {
if (mActionMode != null) {
return false;
}
MyActionModeCallBack mActionModeCallBack = new MyActionModeCallBack(position, dbh);
mActionMode = startSupportActionMode(mActionModeCallback);
return true;
}
});
then define MyActionModeCallBack class like following:
public class MyActionModeCallBack extends ActionMode.Callback{
int position;
DatabaseHelper dbh;
public MyActionModeCallBack(int position, dbh){
this.position = position;
this.dbh = dbh;
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
dbh.delete(position);// what ever your getter setter name is
myValues.remove(position);
dataAdapter.notifyDataSetChanged();
mode.finish();
return true;
case R.id.edit:
Toast.makeText(ViewList.this, "Edited", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
Make a few changes to make code working with multiple selected values.
Add the following code into your activity class:-
private boolean multiSelect = false;
private ArrayList<Integer> selectedItems = new ArrayList<Integer>();
void selectItem(Integer item) {
if (multiSelect) {
if (selectedItems.contains(item)) {
selectedItems.remove(item);
}
else {
selectedItems.add(item);
}
}
}
private ActionMode.Callback actionModeCallbacks = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
multiSelect = true;
menu.add("Delete");
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
for (Integer intItem : selectedItems) {
myValues.remove(intItem);
// pass the long id of the item seleted in the delete method.
int c = dbh.delete(myValues.get(intItem).getId());
if(c >0) { // deleted}
else { // not deleted }
}
mode.finish();
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
multiSelect = false;
selectedItems.clear();
notifyDataSetChanged();
}
};
Change the setOnItemClickListener as below:-
dataAdapter.setOnItemClickListener(new RecyclerViewItemClickListener() {
#Override
public boolean onItemLongClick(View view, int position) {
if (mActionMode != null) {
return false;
}
mActionMode = startSupportActionMode(mActionModeCallback);
selectItem(position);
return true;
}
});
Please make few changes as per your menu in onCreateActionMode and onActionItemClicked.
All the seleted items will be add to the arraylist , it can be used for your different operations and the boolean multiSelect will allow you to unselect the already selected items.
For Reference:-
Contextual Action Bars: Removing Items from a RecyclerView
Try changing you delete function as follows :-
public int delete(long id) {
SQLiteDatabase db = this.getWritableDatabase();
int count= db.delete(TABLE_NAME, "id = ?", new String[]{String.valueOf(id)});
return count; // no. of rows deleted
}
Actionbar callback flow :-
The first method is onCreateActionMode. This method is called once when the ActionMode is first created and is where we should set up the Menu.Also, since this is called when we’re first entering the ActionMode(on long pressing a item), it’s a good place to set our ‘multiSelect’ variable.
Moving onto ‘onPrepareActionMode’, this method will be called anytime the CAB is invalidated. So if you want to update your CAB while it’s being displayed, this would be the place to do it, and you’d want to return true to tell Android that you’ve updated the CAB, otherwise if you do not need to update leave it as same.
onActionItemClickedthis method is called whenever one of your CAB’s MenuItems is clicked.we need to do all the delete operations here on the selected items and then call mode.finish(), which tells Android that we’re done with the CAB and results in a call to onDestroyActionMode.
onDestroyActionMode ,after this point the CAB will no longer be displayed, so this is a good spot to set ‘multiSelect’ to false as well as clear out our ‘selectedItems’ list. It’s also a good place to call ‘notifyDataSetChanged()’ to make sure that we’re keeping our adapter up to date with our ‘items’ List:
note :- CAB here denotes our contextual action bar.
Replace:-
Cursor data = dbh.getListContents();
if (data.getCount() != 0) {
while (data.moveToNext()) {
String str1 = data.getString(1);
String str2 = data.getString(2);
long id = data.getLong(0); // add this ,line gets the id
Data d = new Data(str1, str2);
d.setId(id); //set the id
myValues.add(d);
dataAdapter = new DataAdapter(myValues);
rv.setAdapter(dataAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rv.setLayoutManager(layoutManager);
}
}
Related
I am doing an app which auto-scrolls images, at the bottom of the screen there is a static layout, which I need to display the value of images that have already passed (i.e. position).
I get the correct value of images passed by implementing :
int position = holder.getAdapterPosition();
in the RecyclerViewListAdapter.java
now I need to display this value in the RecyclerViewListActivity.java
on a text view at the static layout beneath the Recycler view?
public class RecyclerViewListAdapter extends RecyclerView.Adapter {
Context context;
List<Data> dataList;
private SharedPreferences preferences;
public RecyclerViewListAdapter(Context context, List<Data> dataList) {
this.context = context;
this.dataList = dataList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_recycler_list, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.mImage.setImageResource(dataList.get(position).getImage());
holder.mImage.setImageResource(dataList.get(position).getImage());
**int position = holder.getAdapterPosition();**
}
#Override
public int getItemCount() {
if (dataList == null || dataList.size() == 0)
return 0;
return dataList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView mNumberText,mText;
ImageView mImage;
LinearLayout mLinearLayout;
public MyViewHolder(View itemView) {
super(itemView);
mImage = (ImageView) itemView.findViewById(R.id.quran_page);
mLinearLayout = (LinearLayout) itemView.findViewById(R.id.linearLayout);
}
}
}
public class RecyclerViewListActivity extends AppCompatActivity {
RecyclerView mListRecyclerView;
ArrayList<Data> dataArrayList;
RecyclerViewListAdapter recyclerViewListAdapter ;
Runnable updater;
private boolean isTouch = false;
TextViewRemaining;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_view_list);
final TextView TextViewRemaining = (TextView) findViewById(R.id.TextViewRemaining);
**TextViewRemaining.setText("Position: "+position);**
initializeView();
mListRecyclerView.addOnItemTouchListener(new RecyclerTouchListener(this,
mListRecyclerView, new ClickListener() {
#Override
public void onClick(View view, int position) {
}
#Override
public void onLongClick(View view, int position) {
Toast.makeText(RecyclerViewListActivity.this, "Long press on position :" + position,
Toast.LENGTH_LONG).show();
}
}));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
return super.onOptionsItemSelected(item);
}
public static interface ClickListener{
public void onClick(View view,int position);
public void onLongClick(View view,int position);
}
class RecyclerTouchListener implements RecyclerView.OnItemTouchListener{
private ClickListener clicklistener;
private GestureDetector gestureDetector;
//#RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
public RecyclerTouchListener(Context context, final RecyclerView recycleView, final ClickListener clicklistener){
this.clicklistener=clicklistener;
gestureDetector=new GestureDetector(context,new GestureDetector.SimpleOnGestureListener(){
#Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
#Override
public void onLongPress(MotionEvent e) {
View child=recycleView.findChildViewUnder(e.getX(),e.getY());
if(child!=null && clicklistener!=null){
clicklistener.onLongClick(child,recycleView.getChildAdapterPosition(child));
}
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child=rv.findChildViewUnder(e.getX(),e.getY());
if(child!=null && clicklistener!=null && gestureDetector.onTouchEvent(e)){
clicklistener.onClick(child,rv.getChildAdapterPosition(child));
}
return false;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
private void initializeView()
{
mListRecyclerView = (RecyclerView) findViewById(R.id.vR_recyclerViewList);
setValues();
}
private void setValues(){
prepareData();
recyclerViewListAdapter = new RecyclerViewListAdapter(RecyclerViewListActivity.this,dataArrayList);
mListRecyclerView.setLayoutManager(new LinearLayoutManager(RecyclerViewListActivity.this)); // original
mListRecyclerView.setItemAnimator(new DefaultItemAnimator());
mListRecyclerView.setHasFixedSize(false);
mListRecyclerView.setAdapter(recyclerViewListAdapter);
recyclerViewListAdapter.notifyDataSetChanged();
final int speedScroll = 2000; //default is 2000 it need to be 30000
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
int count = 0;
// boolean flag = true;
#Override
public void run() {
boolean x=true;
// while(x) {
if (count < recyclerViewListAdapter.getItemCount()) {
if (count == recyclerViewListAdapter.getItemCount() - 1) {
flag = false;
} else if (count == 0) {
flag = true;
}
}
if (flag) count++;
// else count--;
mListRecyclerView.smoothScrollToPosition(count);
handler.postDelayed(this, speedScroll);
}
};
handler.postDelayed(runnable,speedScroll);
}
private void prepareData(){
dataArrayList = new ArrayList<>();
Data data1 = new Data();
data1.setImage(R.drawable.p1);
dataArrayList.add(data1);
Data data2 = new Data();
data2.setImage(R.drawable.p2);
dataArrayList.add(data2);
Data data3 = new Data();
data3.setImage(R.drawable.p3);
dataArrayList.add(data3);
Data data4 = new Data();
data4.setImage(R.drawable.p4);
dataArrayList.add(data4);
Data data5 = new Data();
data5.setImage(R.drawable.p5);
dataArrayList.add(data5);
}
}
So, How can I show the position value on textView in a real-time, as position is a dynamic value, I expect the output on the textView to change as the images passed to the top.
Many Thanks in advance.
This how I solve my problem:
I save the position value in a power Preference(an easier version of shared Preferences)-many thanks to:
Ali Asadi(https://android.jlelse.eu/powerpreference-a-simple-approach-to-store-data-in-android-a2dad4ddc4ac)
I use a Thread that updates the textview every second-many thanks to:
https://www.youtube.com/watch?v=6sBqeoioCHE&t=149s
Thanks for all.
I'm trying to retrieve all the checkboxes from my RecyclerView in order to uncheck them. However, this error is shown. Below are the classes that LogCat points to.
java.lang.IllegalArgumentException: itemView may not be null
at android.support.v7.widget.RecyclerView$ViewHolder.<init>(RecyclerView.java:10314)
at br.com.ufrn.marceloaugusto.tasklist.adapter.ProdutoAdapter$ProdutosViewHolder.<init>(ProdutoAdapter.java:0)
at br.com.ufrn.marceloaugusto.tasklist.MainActivity.onOptionsItemSelected(MainActivity.java:93)
MainActivity.java
public class MainActivity extends BaseActivity {
//private SQLiteDatabase banco;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUpToolbar();
if (savedInstanceState == null) {
FragmentProdutos frag = new FragmentProdutos();
getSupportFragmentManager().beginTransaction().add(R.id.container, frag).commit();
}
//FAB
findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
snack(view, "Adicionar produto");
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_desmarkAll) {
RecyclerView recycler = (RecyclerView) findViewById(R.id.recyclerView);
ProdutoAdapter.ProdutosViewHolder holder = null;
int id = 0;
for (int i = 0; i < recycler.getAdapter().getItemCount(); i++) {
holder = new ProdutoAdapter.ProdutosViewHolder(recycler.getChildAt(i)); **//Line 93**
if (holder.checkBox.isChecked()) {
holder.checkBox.setChecked(false);
}
}
return true;
}
return super.onOptionsItemSelected(item);
}}
ProdutoAdapter.java
public class ProdutoAdapter extends RecyclerView.Adapter<ProdutoAdapter.ProdutosViewHolder> {
private final Context context;
private final List<Produto> produtos;
//Interface para expor os eventos de toque na lista
private ProdutoOnClickListener produtoOnClickListener;
private ProdutoOnCheckListener produtoOnCheckListener;
public ProdutoAdapter(Context context, List<Produto> produtos, ProdutoOnClickListener produtoOnClickListener, ProdutoOnCheckListener produtoOnCheckListener) {
this.context = context;
this.produtos = produtos;
this.produtoOnClickListener = produtoOnClickListener;
this.produtoOnCheckListener = produtoOnCheckListener;
}
#Override
public int getItemCount() {
return this.produtos != null ? this.produtos.size() : 0;
}
#Override
public ProdutosViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.adapter_produto, parent, false);
ProdutosViewHolder holder = new ProdutosViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(final ProdutosViewHolder holder, final int position) {
Produto p = produtos.get(position);
holder.tNome.setText(p.getNome());
//holder.tPreco.setText(String.valueOf(p.getPreco()));
if (produtoOnClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
produtoOnClickListener.onClickProduto(view, position);
}
});
}
if (produtoOnCheckListener != null) {
holder.checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
produtoOnCheckListener.onCheckProduto(view, position);
}
});
}
}
public interface ProdutoOnClickListener {
public void onClickProduto(View view, int idx);
}
public interface ProdutoOnCheckListener {
public void onCheckProduto(View view, int position);
}
public static class ProdutosViewHolder extends RecyclerView.ViewHolder {
public TextView tNome;
//public TextView tPreco;
CardView cardView;
public CheckBox checkBox;
public ProdutosViewHolder(View view) {
super(view);
tNome = (TextView) view.findViewById(R.id.nomeProduto);
//tPreco = (TextView) view.findViewById(R.id.precoProduto);
cardView = (CardView) view.findViewById(R.id.card_view);
checkBox = (CheckBox) view.findViewById(R.id.checkProduto);
}
}
}
Method getChildAt is method of ViewGroup, so recycler.getChildAt(i) will be null for you. In your case you should use produtos list, iterate over it and set its field associated to "checked" state to "false", invoke notifyDataSetChanged() method of your adapter and then onBindViewHolder() will automatically change holder's checkBox values.
So instead of
for (int i = 0; i < recycler.getAdapter().getItemCount(); i++) {
holder = new ProdutoAdapter.ProdutosViewHolder(recycler.getChildAt(i)); **//Line 93**
if (holder.checkBox.isChecked()) {
holder.checkBox.setChecked(false);
}
}
use this one:
for (Product product : produtos){
product.setChecked(false);
}
recycler.getAdapter().notifyDataSetChanged();
I supppose your class Project has such method.
In a RecyclerView the item views are recycled so you dont have as many itemviews as item in your List. Instead those itemviews are recycled and shows differents elements of your productos List.
Your problem is that you are in a for loop with the length of the List but inside you are using that index to access itemviews wich has not that much elements.
Instead, you should define a variable in Producto.class and update every time that check/uncheck the CheckBox of the item. And set this variable to false when you want to uncheck all and call
adapter.notifyDataSetChanged();
UPDATE:
ProdutoAdapter.java
Define a method to access list produtos and update onBindViewHolder like this:
if (produtoOnCheckListener != null) {
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
produtos.get(position).setCheckBoxState(b);
produtoOnCheckListener.onCheckProduto(view, position);
}
});
}
MainActivity.class Define a ProductoAdapter variable and access to list productos to update the boolean value of each producto
[...]
ProductoAdapter productoAdapter = new ProductoAdapter();
[...]
for (int i = 0; i < productoAdapter.getItemCount(); i++) {
productoAdapter.getListProductos().get(i).setCheckBoxState(false);
}
productoAdapter.notifyDataSetChanged();
When in SettingsActivity switch on to show only selected with checkbox and my List contains near 30 items, recyclerview scrolls normally, but when I use List with 900 items - recyclerview scrolls with freezes. Where my way to update recyclerview is wrong?
Android Studio log:
E/RecyclerView: No adapter attached; skipping layout
I/Choreographer: Skipped 68 frames! The application may be doing too much work on its main thread.
BikesAdapter:
public class BikesAdapter extends RecyclerView.Adapter<BikesAdapter.BikesViewHolder>{
private static final String PREFS_NAME = "bikes_prefs";
public static List<Categories> categories;
private Context context;
public BikesAdapter(Context context) {
this.context = context;
notifyDataSetChanged();
}
#Override
public BikesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new BikesViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.list_bikes, parent, false));
}
#Override
public void onBindViewHolder(final BikesViewHolder holder, final int position) {
final SharedPreferences setFavoritesCnB = FragmentBikesListXT.context.getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
boolean isFavoriteChB = setFavoritesCnB.getBoolean(categories.get(position).title, false);
holder.cbStars.setChecked(isFavoriteChB);
holder.cbStars.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SharedPreferences.Editor editor = setFavoritesCnB.edit();
editor.putBoolean(categories.get(position).title, holder.cbStars.isChecked());
editor.apply();
if (holder.cbStars.isChecked()) {
openDBHelper.save(position);
Constants.CATEGORIES.add(categories.get(position));
} else {
openDBHelper.delete(position);
Constants.CATEGORIES.remove(categories.get(position));
}
}
});
if (checkSwitch) {
if (!isFavoriteChB) {
holder.cardView.setVisibility(View.GONE);
} else {
holder.textTitle.setText(categories.get(position).title);
}
} else holder.textTitle.setText(categories.get(position).title);
holder.textTitle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(categories.get(position).link));
context.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return categories.size();
}
public class BikesViewHolder extends RecyclerView.ViewHolder {
private CardView cardView;
private CheckBox cbStars;
private TextView textTitle;
public BikesViewHolder(View itemView) {
super(itemView);
cardView = (CardView) itemView.findViewById(R.id.cardView);
cbStars = (CheckBox) itemView.findViewById(R.id.cbStars);
textTitle = (TextView) itemView.findViewById(R.id.tv_title_bike);
}
}
}
Fragment with recyclerview:
public class FragmentBikesListXT extends Fragment {
public static RecyclerView rvBikes;
public static ProgressBar pbBikes;
public static Context context;
public static CreateDBHelper dbHelper;
public static OpenDBHelper openDBHelper;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
FrameLayout layout = (FrameLayout) inflater.inflate(R.layout.fragment_bikes_list_xt, container, false);
rvBikes = (RecyclerView) layout.findViewById(R.id.rvBikes);
pbBikes = (ProgressBar) layout.findViewById(R.id.pbBikes);
SharedPreferences setSwitch = getActivity().getSharedPreferences(PREFS_LIST, MODE_PRIVATE);
checkSwitch = setSwitch.getBoolean("NameOfThingToSave", false);
context = getContext();
dbHelper = new CreateDBHelper(this.getActivity());
openDBHelper = new OpenDBHelper();
initIO(Constants.URL_FULL_LIST);
return layout;
}
public void initIO(String url) {
ParseXT.initializeData(url);
rvBikes.setHasFixedSize(true);
rvBikes.setLayoutManager(new GridLayoutManager(this.getActivity(), 1));
}
}
SettingsActivity:
public class SettingsActivity extends AppCompatActivity {
private Switch mSwitch;
public static boolean checkSwitch;
public static final String PREFS_LIST = "list_prefs";
public static Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
mSwitch = (Switch) findViewById(R.id.switch_list);
SharedPreferences setSwitch = getSharedPreferences(PREFS_LIST, MODE_PRIVATE);
mSwitch.setChecked(setSwitch.getBoolean("NameOfThingToSave", false));
mSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
if(isChecked){
checkSwitch = true;
SharedPreferences.Editor editor = getSharedPreferences(PREFS_LIST, MODE_PRIVATE).edit();
editor.putBoolean("NameOfThingToSave", true);
editor.commit();
}else{
checkSwitch = false;
SharedPreferences.Editor editor = getSharedPreferences(PREFS_LIST, MODE_PRIVATE).edit();
editor.putBoolean("NameOfThingToSave", false);
editor.commit();
}
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
super.onBackPressed();
return true;
}
finish();
return super.onOptionsItemSelected(item);
}
}
OpenDBHelper:
public class OpenDBHelper implements IDBHelper {
private SQLiteDatabase db;
#Override
public void read() {
db = FragmentBikesListXT.dbHelper.getWritableDatabase();
BikesAdapter.categories.clear();
Cursor c = db.query(Constants.TABLE_BIKE, null, null, null, null, null, null);
if (c.moveToFirst()) {
int titleColIndex = c.getColumnIndex(Constants.FIELD_TITLE);
int linkColIndex = c.getColumnIndex(Constants.FIELD_LINK);
do {
BikesAdapter.categories.add(new Categories(
c.getString(titleColIndex),
c.getString(linkColIndex)));
Log.d("DBHelper", "READ ID = " + c.getString(titleColIndex));
} while (c.moveToNext());
} else
c.close();
}
#Override
public void save(int position) {
ContentValues cv = new ContentValues();
db = FragmentBikesListXT.dbHelper.getWritableDatabase();
cv.put(Constants.FIELD_TITLE, BikesAdapter.categories.get(position).title);
cv.put(Constants.FIELD_LINK, BikesAdapter.categories.get(position).link);
long size = db.insert(Constants.TABLE_BIKE, null, cv);
Log.d("DBHelper", "SAVE row inserted, size " + size + " ID = , " + BikesAdapter.categories.get(position).title);
FragmentBikesListXT.dbHelper.close();
}
#Override
public void delete(int position) {
db = FragmentBikesListXT.dbHelper.getWritableDatabase();
String[] whereArgs = {String.valueOf(BikesAdapter.categories.get(position).title)};
db.delete(Constants.TABLE_BIKE, Constants.FIELD_TITLE + " = ?", whereArgs);
Log.d("DBHelper", "DELETE ID = " + BikesAdapter.categories.get(position).title);
db.close();
}
}
And parser class:
public class ParseXT {
private static Elements titleTxt;
private static Elements linkTxt;
private static ArrayList<String> titleList = new ArrayList<>();
private static ArrayList<String> linkList = new ArrayList<>();
public static BikesAdapter bikesAdapter = new BikesAdapter(FragmentBikesListXT.context);
public static void initializeData(String url) {
new NewTreadParsed(url).execute();
}
public static class NewTreadParsed extends AsyncTask<List<Categories>, Void, List<Categories>> {
private String url;
public NewTreadParsed(String url) {
this.url = url;
}
#Override
protected List<Categories> doInBackground(List<Categories>... params) {
Document doc;
List<Categories> categories = new ArrayList<>();
try {
doc = Jsoup.connect(url).get();
titleTxt = doc.select(".topictitle");
linkTxt = doc.select(".a[href]");
titleList.clear();
linkList.clear();
for (Element contents : titleTxt) {
titleList.add(contents.text());
}
for (Element contents1 : titleTxt) {
Element element = contents1.select("a[href]").first();
linkList.add(element.attr("abs:href"));
}
}
catch (IOException e){
e.printStackTrace();
}
for (int i = 0; i < titleList.size(); i++) {
categories.add(new Categories(titleList.get(i), linkList.get(i)));
}
return categories;
}
#Override
protected void onPostExecute(List<Categories> categories) {
super.onPostExecute(categories);
FragmentBikesListXT.pbBikes.setVisibility(ProgressBar.INVISIBLE);
BikesAdapter.categories = categories;
FragmentBikesListXT.rvBikes.setAdapter(bikesAdapter);
}
}
}
Use notifyDataSetChanged()
If you are writing an adapter it will always be more efficient to use the more specific change events if you can. Rely on notifyDataSetChanged()
I am currently trying to make a simple task killer for learning purpose, I created a list view that show all user installed apps with checkbox, so user could select with apps should be killed when screen off.
But I am stuck at how to save the checkbox state and get the checked app's package name
I have search stack overflow a long time but still don't know how to do it, please help me, thanks
This is my code
AppAdapter.java
public class AppAdapter extends BaseAdapter {
private LayoutInflater layoutInflater;
private List<AppList> listStorage;
public AppAdapter(Context context, List<AppList> customizedListView) {
layoutInflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
listStorage = customizedListView;
}
#Override
public int getCount() {
return listStorage.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder listViewHolder;
if(convertView == null){
listViewHolder = new ViewHolder();
convertView = layoutInflater.inflate(R.layout.installed_app_list, parent, false);
listViewHolder.textInListView = (TextView)convertView.findViewById(R.id.list_app_name);
listViewHolder.imageInListView = (ImageView)convertView.findViewById(R.id.app_icon);
listViewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(listViewHolder);
listViewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
listViewHolder.checkBox.setSelected(listStorage.get(position).isSelected());
}
}
});
}else{
listViewHolder = (ViewHolder)convertView.getTag();
}
listViewHolder.textInListView.setText(listStorage.get(position).getName());
listViewHolder.imageInListView.setImageDrawable(listStorage.get(position).getIcon());
listViewHolder.checkBox.setChecked(listStorage.get(position).isSelected());
return convertView;
}
static class ViewHolder{
TextView textInListView;
ImageView imageInListView;
CheckBox checkBox;
}
}
Applist.java
public class AppList {
private String name;
Drawable icon;
private static final String PREFERENCES_NAMESPACE = "checkboxes_states";
boolean selected = false;
private SharedPreferences mSettings;
private SharedPreferences.Editor mEditor;
public AppList(Context context, String name, Drawable icon) {
this.name = name;
this.icon = icon;
mSettings = context.getSharedPreferences(PREFERENCES_NAMESPACE, 0);
mEditor = mSettings.edit();
setSelected(mSettings.getBoolean(name, selected));
}
public String getName() {
return name;
}
public Drawable getIcon() {
return icon;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
if(this.selected != selected) { // update if changed
mEditor.putBoolean(getName(), selected);
mEditor.apply();
this.selected = selected;
}
}
}
MainActivity.java
public class MainActivity extends Activity {
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
ListView userInstalledApps = (ListView)findViewById(R.id.installed_app_list);
List<AppList> installedApps = getInstalledApps();
AppAdapter installedAppAdapter = new AppAdapter(MainActivity.this, installedApps);
userInstalledApps.setAdapter(installedAppAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private List<AppList> getInstalledApps() {
List<AppList> res = new ArrayList<AppList>();
List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);
for (int i = 0; i < packs.size(); i++) {
PackageInfo p = packs.get(i);
if ((isSystemPackage(p) == false)) {
String appName = p.applicationInfo.loadLabel(getPackageManager()).toString();
Drawable icon = p.applicationInfo.loadIcon(getPackageManager());
res.add(new AppList(context, appName, icon));
}
}
return res;
}
private boolean isSystemPackage(PackageInfo pkgInfo) {
return ((pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ? true : false;
}
}
Thanks in advance
Create interface:
public interface AppSelector {
void selectApp(String appName);
void removeApp(String appName);
boolean isSelected(String appName);
}
Add it to your AppAdapter:
public class AppAdapter extends BaseAdapter {
private AppSelector appSelector;
private List<AppList> listStorage;
public AppAdapter(AppSelector appSelector, List<AppList> customizedListView) {
this.appSelector = appSelector;
listStorage = customizedListView;
}
....
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder listViewHolder;
if(convertView == null){
listViewHolder = new ViewHolder();
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.installed_app_list, parent, false);
listViewHolder.textInListView = (TextView)convertView.findViewById(R.id.list_app_name);
listViewHolder.imageInListView = (ImageView)convertView.findViewById(R.id.app_icon);
listViewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(listViewHolder);
listViewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
appSelector.selectApp(listStorage.get(position).getName());
} else {
appSelector.removeApp(listStorage.get(position).getName());
}
}
});
} else {
listViewHolder = (ViewHolder)convertView.getTag();
}
listViewHolder.textInListView.setText(listStorage.get(position).getName());
listViewHolder.imageInListView.setImageDrawable(listStorage.get(position).getIcon());
listViewHolder.checkBox.setChecked(appSelector.isSelected(listStorage.get(position).getName()));
return convertView;
}
....
}
Implement in by your MainActivity:
class MainActivity extends AppCompatActivity implements AppSelector {
private static final String PREFERENCES_NAMESPACE = "checkboxes_states";
private SharedPreferences checkedAppsPreferences;
....
#Override
protected void onCreate(Bundle savedInstanceState) {
....
checkedAppsPreferences = getSharedPreferences(PREFERENCES_NAMESPACE, 0);
....
AppAdapter installedAppAdapter = new AppAdapter(this, installedApps);
....
}
#Override
public void selectApp(String appName) {
checkedAppsPreferences.edit()
.putBoolean(appName, true)
.apply();
}
#Override
public void removeApp(String appName) {
checkedAppsPreferences.edit()
.remove(appName)
.apply();
}
#Override
public boolean isSelected(String appName) {
return checkedAppsPreferences.contains(appName) && checkedAppsPreferences.getBoolean(appName, false);
}
....
}
Your AppList class should not contains any references to Context or SharedPreferences and logic for "checking"/"unchecking". It should be simple POJO.
Using interface you can easily replace shared preferences with another kind of repository like SQLite
EDITED: I change AppAdapter getView mwthod:
listViewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
appSelector.selectApp(listStorage.get(position).getName());
} else {
appSelector.removeApp(listStorage.get(position).getName());
}
}
});
You can check full project at https://github.com/valeragit/AppListExample
You never called AppList.setSelected().
Call than on listViewHolder onClickListener and then probaby notify the adapter that there are changes.
You also probably want to call setChecked rather than setSelected
listViewHolder.checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean isSelected = listStorage.get(position).isSelected();
listViewHolder.checkBox.setChecked(!isSelected);
listStorage.get(position).setSelected(!isSelected)
notifyDataSetChanged();
}
});
You can further improve this by setting a checkChangedListener rather than an onClickListener, but solve the initial problem first.
Edit: OP Solved the initial problem, now commenting for improvements.
Replace onClick with this:
listViewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
listStorage.get(position).setSelected(isChecked)
notifyDataSetChanged();
}
});
Adding and removing items from RecyclerView is working, but i don't know if i have written a good method in database for deleting rows because only i'm saving condition when item is added and when it is removed and if i leave from app and come back, but previosly i have deleted some items, i'm seeing them there. So i need some help about this method in database for removing items and also implementing it in activity.
Here are my code:
DATABASE:
public class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "items.db";
private static final int DATABASE_VERSION = 1;
private final String TABLE_ITEMS = "items";
private final String COLUMN_ID = "id";
private final String COLUMN_ITEM = "item";
private static DBHelper dbh;
private DBHelper(Activity activity) {
super(activity, DATABASE_NAME, null, DATABASE_VERSION);
}
public static synchronized DBHelper getConnection(Activity activity) {
if (dbh == null)
dbh = new DBHelper(activity);
return dbh;
}
#Override
public void onCreate(SQLiteDatabase db) {
String upitZaPravljanjeBaze =
"CREATE TABLE "+TABLE_ITEMS+"("+COLUMN_ID+" INTEGER PRIMARY KEY, "+COLUMN_ITEM+" TEXT);";
db.execSQL(upitZaPravljanjeBaze);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion) {
db.execSQL("DROP TABLE" + "TABLE_ITEMS");
onCreate(db);
}
}
public ArrayList<String> getAllItems() {
ArrayList<String> toRet = new ArrayList<String>();
SQLiteDatabase db = getReadableDatabase();
Cursor c = db.rawQuery("SELECT * FROM " + TABLE_ITEMS, null);
c.moveToFirst();
while(c.isAfterLast() == false) {
toRet.add(c.getString(c.getColumnIndex(COLUMN_ITEM)));
c.moveToNext();
}
return toRet;
}
public long saveItem(String item) {
SQLiteDatabase db = getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(COLUMN_ITEM, item);
return db.insert(TABLE_ITEMS, null, cv);
}
public boolean deleteItem(long rowId) {
SQLiteDatabase db = getReadableDatabase();
return db.delete(TABLE_ITEMS, COLUMN_ID + "=" + rowId, null) > 0;
}
}
ADAPTER:
public class AdapterRecyclerAnimators extends RecyclerView.Adapter<AdapterRecyclerAnimators.Holder> {
private ArrayList<String> mListData = new ArrayList<>();
private LayoutInflater mLayoutInflater;
public AdapterRecyclerAnimators(Context context) {
mLayoutInflater = LayoutInflater.from(context);
}
#Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View row = mLayoutInflater.inflate(R.layout.custom_row_item, parent, false);
Holder holder = new Holder(row);
return holder;
}
#Override
public void onBindViewHolder(Holder holder, final int position) {
String data = mListData.get(position);
holder.textDataItem.setText(data);
holder.buttonDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
removeItem(position);
}
});
}
public void addItem(String item) {
mListData.add(item);
notifyItemInserted(mListData.size());
}
public void addAll(ArrayList<String> newList){
mListData = newList;
notifyDataSetChanged();
}
public void removeItem(String item) {
int position = mListData.indexOf(item);
if (position != -1) {
mListData.remove(item);
notifyItemRemoved(position);
}
}
public void removeItem(int position) {
mListData.remove(position);
notifyItemRemoved(position);
}
#Override
public int getItemCount() {
return mListData.size();
}
public static class Holder extends RecyclerView.ViewHolder {
TextView textDataItem;
ImageButton buttonDelete;
public Holder(View itemView) {
super(itemView);
textDataItem = (TextView) itemView.findViewById(R.id.text_item);
buttonDelete = (ImageButton) itemView.findViewById(R.id.button_delete);
}
}
}
MAIN ACTIVITY:
public class MainActivity extends BaseActivity {
//int containing the duration of the animation run when items are added or removed from the RecyclerView
public static final int ANIMATION_DURATION = 2000;
//edit text letting the user type item name to be added to the recylcerview
private EditText mInput;
//itemcounter for recyclerview
private TextView mItemCounter;
//recyclerview showing all items added by the user
private RecyclerView mRecyclerView;
private AdapterRecyclerAnimators mAdapter;
ArrayList<String> mListData = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initViews();
if(savedInstanceState != null){
ArrayList<String> items = savedInstanceState.getStringArrayList("items");
mListData.addAll(items);
mAdapter.notifyDataSetChanged();
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putStringArrayList("items", mListData);
}
private void initViews(){
mInput = (EditText) findViewById(R.id.text_input);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerAnimatedItems);
mItemCounter = (TextView) findViewById(R.id.itemCounter);
mItemCounter.setText(String.valueOf(mRecyclerView.getChildCount()));
mAdapter = new AdapterRecyclerAnimators(this);
//set an animator on the RecyclerView that works only when items are added or removed
mRecyclerView.setItemAnimator(new SlideInLeftAnimator());
mRecyclerView.getItemAnimator().setAddDuration(ANIMATION_DURATION);
mRecyclerView.getItemAnimator().setRemoveDuration(ANIMATION_DURATION);
mAdapter.addAll(DBHelper.getConnection(MainActivity.this).getAllItems());
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}
public void addItem(View view) {
//check if the EditText has valid contents
if (Util.hasValidContents(mInput)) {
DBHelper.getConnection(MainActivity.this)
.saveItem(mInput.getText().toString());
ArrayList<String> allItems = DBHelper.getConnection(MainActivity.this).getAllItems();
mAdapter.addAll(allItems);
mInput.setText("");
}
}
#Override
protected int getLayoutResourceId() {
return R.layout.activity_main;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
These are your delete methode:
public void removeItem(String item) {
int position = mListData.indexOf(item);
if (position != -1) {
mListData.remove(item);
notifyItemRemoved(position);
}
}
public void removeItem(int position) {
mListData.remove(position);
notifyItemRemoved(position);
}
You remove the items from your list but you never remove them from your database. Call your delete method in both of of these methods and see if it works.
Don't necessarily think this will fix your problem but thought I would point it out, In your database delete method you have:
SQLiteDatabase db = getReadableDatabase();
You probably want to switch that:
SQLiteDatabase db = getWritableDatabase();