Recyclerview is not updated after deleting from the sqlite database - android

I am new in android. I am using content provider for my app and want to delete an item from my sqlite database. it deletes the item from the database but the recyclerview does not show that it has been deleted except you go back and open the activity again before the deleted item disappears. I have looked through the code but I dont actually know what the problem is.
MainActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_selecte_problem_drawal);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitleTextColor(Color.parseColor("#FFFFFF"));
mRecyclerView = (RecyclerView) findViewById(R.id.selected_problem_recycle_view); // Instantiate Recyclerview
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(linearLayoutManager);
mRecyclerView.setHasFixedSize(true);
selectedProblemsAdapter = new SelectedProblemsAdapter(this, null);
mRecyclerView.setAdapter(selectedProblemsAdapter);
getLoaderManager().initLoader(SELECTED_PROBLEMS_LOADER_ID, null,new CartLoader());
payForSelectedProblems = (Button)findViewById(R.id.payForSelectedProblems);
payForSelectedProblems.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (total > 0) {
Preferences.setDefaults("total", String.valueOf(total), getApplicationContext());
Intent intent = new Intent(SelectedProblems.this, SecondPayment.class);
startActivity(intent);
}else{
AlertDialog.Builder alert = new AlertDialog.Builder(SelectedProblems.this);
alert.setTitle("Alert");
alert.setMessage("Kindly Select a problem to continue...");
alert.setPositiveButton("OK",null);
alert.show();
}
}
});
}
public class CartLoader implements LoaderManager.LoaderCallbacks<Cursor> {
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new CursorLoader(
SelectedProblems.this,
TranxavContract.CartEntries.CONTENT_URI,
SELECTED_PROBLEMS,
null,
null,
null
);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
selectedProblemsAdapter.update(cursor);
total = getSelectedProblemTotal(cursor);
problemSelectedTotal.setText(CurrencyFormatter.currencyFormat(String.valueOf(total)));
}
#Override
public void onLoaderReset(Loader<Cursor> loader){
selectedProblemsAdapter.update(null);
}
public double getSelectedProblemTotal(Cursor cursor){
while (cursor.moveToNext()){
total = total + Double.parseDouble(cursor.getString(SelectedProblems.PRICE));
}
return total;
}
}
Adapter
public SelectedProblemsAdapter(Context context, Cursor cursor) {
this.context = context;
this.cursor = cursor;
}
#NonNull
#Override
public SelectedProblemsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.activity_selected_problems_content, null, false);
return new SelectedProblemsViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull SelectedProblemsViewHolder holder, final int position) {
if (this.cursor != null){
this.cursor.moveToPosition(position);
priceIndex = cursor.getColumnIndex(TranxavContract.CartEntries.PRICE);
problemsIndex = cursor.getColumnIndex(TranxavContract.CartEntries.PROBLEMS);
id = cursor.getString(idIndex);
problems = cursor.getString(problemsIndex);
price = cursor.getString(priceIndex);
formatted_price = CurrencyFormatter.currencyFormat(price);
holder.selectedProblemPrice.setText(formatted_price);
holder.selectedProblems.setText(problems);
holder.remove_problem_from_cart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
context.getContentResolver().delete(
TranxavContract.CartEntries.CONTENT_URI,
TranxavContract.CartEntries.PROBLEMS + " = ?",
new String[] { problems }
);
Toast.makeText(context, problems + " Item Removed from Problem Selected" + "with postion " + position, Toast.LENGTH_SHORT).show();
notifyItemRemoved(position);
notifyDataSetChanged();
}
});
}
}
#Override
public int getItemCount() {
return (null != cursor ? cursor.getCount(): 0);
}
public void update(Cursor cursor) {
this.cursor = cursor;
notifyDataSetChanged();
}
class SelectedProblemsViewHolder extends RecyclerView.ViewHolder{
TextView selectedProblems, selectedProblemPrice, selectedProblemTotal;
Button remove_problem_from_cart;
public SelectedProblemsViewHolder(View itemView) {
super(itemView);
selectedProblems = itemView.findViewById(R.id.selected_problems);
selectedProblemPrice = itemView.findViewById(R.id.selected_problem_price);
selectedProblemTotal = itemView.findViewById(R.id.selectedProblemTotal);
remove_problem_from_cart = itemView.findViewById(R.id.remove_problem_from_cart);
}
}
Anybody who can help me.

For every delete, update your adapter like this
selectedProblemsAdapter.notifydatasetchanged();

Assuming all your deleting process is correct and you want to show animation all over your list in RecyclerView.
Instead of using
notifyItemRemoved(position)
you could implement
notifyItemRangeChanged(position, getItemCount());
notifyItemRangeChanged() notifies the RecyclerView Adapter that positions of element in adapter has been changed from position.
Here is a reference for you.
Hope it helps!

May be the problem is the list hasn't been reload after you deleted the record in db. You can try the method getLoaderManager().restartLoader(int id, Bundle args, LoaderCallbacks<D> callback) this should be restart the query and update it from the db. I hope so. Check more at here

After Deleting recall your display method
(If selectedProblemsAdapter.notifydatasetchanged(); this method is not work)

Related

Use dbhelper class in adapter view but it has context that always show null and my method to delete the note is not working?

This is my database helper class:
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "note_db" ;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(Note.CREATE_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Note.TABLE_NAME);
onCreate(sqLiteDatabase);
}
public Long insertnote(String note){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Note.COL_NOTE,note);
Long result = db.insert(Note.TABLE_NAME,null,values);
db.close();
return result;
}
public List<Note> getAllNotes() {
List<Note> notes = new ArrayList<>();
// Select All Query
String selectQuery = "SELECT * FROM " + Note.TABLE_NAME ;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Note note = new Note();
note.setId(cursor.getInt(cursor.getColumnIndex(Note.COL_ID)));
note.setNote(cursor.getString(cursor.getColumnIndex(Note.COL_NOTE)));
notes.add(note);
} while (cursor.moveToNext());
}
// close db connection
db.close();
// return notes list
return notes;
}
public int updateNote(Note note) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Note.COL_NOTE, note.getNote());
// updating row
return db.update(Note.TABLE_NAME, values, Note.COL_ID + " = ?",
new String[]{String.valueOf(note.getId())});
}
public void deleteNote(Note note) {
SQLiteDatabase db = this.getWritableDatabase();
// db.execSQL("DELETE FROM " + Note.TABLE_NAME + "WHERE " + Note.COL_ID +" = " + note.getId() +"" );
db.delete(Note.TABLE_NAME, Note.COL_ID + " = ?",new String[]{String.valueOf(note.getId())});
db.close();
}
}
this is my Main Activity
i have also make adapter in main activity
in the adapter i have used onlongclick listener.
im not much aware about it.
and when i click on alert dialog delete button it does nothing.
help me to get rid of this.
public class MainActivity extends AppCompatActivity {
RecyclerView rv;
RecyclerAdapter adapter;
FloatingActionButton btnadd;
DatabaseHelper db;
List<Note> notesList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = new DatabaseHelper(this);
notesList.addAll(db.getAllNotes());
rv = findViewById(R.id.rv);
btnadd = findViewById(R.id.btnadd);
adapter = new RecyclerAdapter(this, notesList);
adapter.notifyDataSetChanged();
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this);
rv.setLayoutManager(mLayoutManager);
rv.setItemAnimator(new DefaultItemAnimator());
rv.setAdapter(adapter);
btnadd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
addnote();
}
});
}
public void addnote() {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View v = getLayoutInflater().inflate(R.layout.add_note,null);
builder.setView(v);
final AlertDialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.show();
final EditText addnote = v.findViewById(R.id.edtnote);
final Button addbtn = v.findViewById(R.id.addbtn);
final Button cancel = v.findViewById(R.id.cancel);
addbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (addnote.getText().toString().isEmpty()==false){
db.insertnote(addnote.getText().toString());
dialog.dismiss();
Toast.makeText(getApplicationContext(),"Note Added",Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getApplicationContext(),"please add note",Toast.LENGTH_SHORT).show();
}
}
});
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog.cancel();
}
});
}
private void deleteNote(int position) {
// deleting the note from db
db.deleteNote(notesList.get(position));
// removing the note from the list
notesList.remove(position);
}
}
this is recycler adapter class
it is also placed in main activity
class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder>{
Context context;
public List<Note> noteList;
// DatabaseHelper db = new DatabaseHelper(context);
public RecyclerAdapter(Context context,List<Note> noteList){
this.context = context;
this.noteList = noteList;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView notes;
public ViewHolder(final View itemView){
super(itemView);
notes = itemView.findViewById(R.id.note);
}
}
#Override
public ViewHolder onCreateViewHolder(final ViewGroup viewGroup, final int i) {
final Context context = viewGroup.getContext();
View view = LayoutInflater.from(context)
.inflate(R.layout.show_note,viewGroup,false);
final ViewHolder holder = new ViewHolder(view);
final DatabaseHelper db = new DatabaseHelper(context);
holder.notes.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(final View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
View v = LayoutInflater.from(view.getContext()).inflate(R.layout.update_delete_note, null);
final Button update, delete;
update = v.findViewById(R.id.update);
delete = v.findViewById(R.id.delete);
builder.setView(v);
final AlertDialog dialog = builder.create();
dialog.show();
update.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
i get problem over here.
this code does nothing
and also i want to refresh the recyclerview in real time.
please show me how to do that too.
it is like i insert note and after that when i reopen app then it show note in recycler view .
i want to do that in realtime when i add it should suddenly show me added note.
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.e(String.valueOf(context),noteList.get(i).toString());
Note note = noteList.get(i);
db.deleteNote(note);
}
});
return true;
}
});
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int i) {
final Note note = noteList.get(i);
holder.notes.setText(note.getNote());
}
#Override
public int getItemCount() {
return noteList.size();
}
}
try this
final Button update, delete;
update = v.findViewById(R.id.update);
delete = v.findViewById(R.id.delete);
builder.setView(v);
final AlertDialog dialog = builder.create();
update.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("UPDATE BUTTON", "TESTING!!!");
dialog.dismiss();
}
});
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("DELETE BUTTON", "TESTING!!!");
dialog.dismiss();
}
});
// Move this to bottom.
dialog.show();
This is what I mean, since the dialog is working and showing but those buttons are not working. Then monitor your log if it has an output or not.
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.e(String.valueOf(context),noteList.get(i).toString());
Note note = noteList.get(i);
db.deleteNote(note);
notifyDataSetChanged();
}
});
Add notifyDataSetChanged() and it will refresh the adapter because when you call that method than it tells the adapter that the data has been updated and the adapter will update with updated data.Also use this in your update note the same way.Just add this at last after you have finished your required operations.
I am posting the update answer with your code.
First add this method in your adapter
public void refreshData(Context context,List<Note> noteList){
this.context = context;
this.noteList = noteList;
notifyDataSetChanged();
}
The reason is that when ever you insert new item in sqlite than you need to add that item to your list and send the updated list to adapter and in adapter you need to call notifyDataSetChanged(); and adapter will be refreshed.This is suggested way to refresh adapter.
next in Your activity addNote() method change it to:-
public void addnote() {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
View v = getLayoutInflater().inflate(R.layout.add_note,null);
builder.setView(v);
final AlertDialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.show();
final EditText addnote = v.findViewById(R.id.edtnote);
final Button addbtn = v.findViewById(R.id.addbtn);
final Button cancel = v.findViewById(R.id.cancel);
addbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!TextUtils.isEmpty(etInterestName.getText().toString().trim())){
db.insertnote(addnote.getText().toString().trim());
notesList.add(addnote.getText().toString().trim());
adapter.refreshData(this, notesList);
dialog.dismiss();
Toast.makeText(getApplicationContext(),"Note Added",Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getApplicationContext(),"please add note",Toast.LENGTH_SHORT).show();
}
}
});
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog.cancel();
}
});
}
First I changed TextUtils.isEmpty(etInterestName.getText().toString().trim()) Since it a more better way of making sure a edit text is not null or empty and after you insert your item to sqlite simply add it to your list
notesList.add(addnote.getText().toString().trim());
adapter.refreshData(this, notesList);
And then call the refreshData method in your adapter and data will be updated.
Hope this solves your problem and if it does mark the ans as correct!!.
Try this
private void deleteNote(int position) {
dbHelper.deleteNote(noteList.get(position).getId());
noteList.remove(position);
Adapter.notifyItemRemoved(position);
}

Add item to RecyclerView when Contact is clicked

I want to add item to RecyclerView when i choose Contact from contactbook
It's can be use in text view i can but i find how to use in recycler
i get two String like contactname and numberphne from Contact book and i need add it to view and show in recyclerview
Here is my code for RecyclerView Adapter
public class SettingCallAdapter extends RecyclerView.Adapter<SettingCallAdapter.ViewHolder>{
private Context context;
private List<Hospital> data;
private int lastSelectedPosition = 0;
public SettingCallAdapter( Context context , List<Hospital> data){
this.context = context;
this.data = data;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_setting_message_radio , parent , false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Hospital hospital = data.get(position);
holder.name.setText(hospital.getHos_name());
holder.num.setText(hospital.getHos_tel());
holder.selectionState.setChecked(lastSelectedPosition == position);
}
#Override
public int getItemCount() {
return data.size() ;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView name , num;
public RadioButton selectionState;
public ViewHolder(View itemView) {
super(itemView);
name = itemView.findViewById(R.id.set_name);
num = itemView.findViewById(R.id.set_num);
selectionState = itemView.findViewById(R.id.select_state);
selectionState.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
lastSelectedPosition = getAdapterPosition();
notifyDataSetChanged();
}
});
}
}
Here is my MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_setting);
TextView title = findViewById(R.id.toolbar_title);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_back));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onBackPressed();
}
});
title.setText(toolbar.getTitle());
title.setText("การแจ้งเหตุฉุกเฉิน");
mDatabase = FirebaseDatabase.getInstance();
mRef = mDatabase.getReference().child("setting").child("hospital");
set_button = findViewById(R.id.setting_edit_button);
set_button.setOnClickListener(this);
save_button = findViewById(R.id.setting_save_button);
save_button.setOnClickListener(this);
show_num = findViewById(R.id.show_num_call);
add_num = findViewById(R.id.add_num_call);
add_contact_message = findViewById(R.id.add_contact_message);
message = findViewById(R.id.set_message);
message.setEnabled(false);
add_num_call = findViewById(R.id.recycler_add_num_call);
show_num_message_list = findViewById(R.id.recycler_show_num_message);
add_num_message_list = findViewById(R.id.recycler_add_num_message);
select_contact = findViewById(R.id.add_contact_call);
select_contact.setOnClickListener(this);
//Check Keyboard
View view = this.getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()){
Hospital mHospital = dataSnapshot1.getValue(Hospital.class);
list_hospital.add(mHospital);
}
mAdapter = new SettingCallAdapter(SettingActivity.this , list_hospital);
mAdapter.notifyDataSetChanged();
add_num_call.setAdapter(mAdapter);
add_num_call.setHasFixedSize(true);
add_num_call.setLayoutManager(new LinearLayoutManager(SettingActivity.this));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
#Override
public void onClick(View view) {
switch (view.getId())
{
case R.id.setting_edit_button:
set_button.setVisibility(View.GONE);
save_button.setVisibility(View.VISIBLE);
show_num.setVisibility(View.GONE);
add_num.setVisibility(View.VISIBLE);
add_contact_message.setVisibility(View.VISIBLE);
show_num_message_list.setVisibility(View.GONE);
message.setEnabled(true);
addNumSOS();
break;
case R.id.setting_save_button:
save_button.setVisibility(View.GONE);
set_button.setVisibility(View.VISIBLE);
show_num.setVisibility(View.VISIBLE);
add_num.setVisibility(View.GONE);
add_contact_message.setVisibility(View.GONE);
show_num_message_list.setVisibility(View.VISIBLE);
message.setEnabled(false);
addMessageSOS();
break;
case R.id.add_contact_call:
Intent contactIntent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
startActivityForResult(contactIntent , RESULT_PICK_CONTACT);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESULT_PICK_CONTACT && resultCode == RESULT_OK) {
Uri contactUri = data.getData();
Cursor cursor = getContentResolver().query(contactUri, null, null, null, null);
cursor.moveToFirst();
int phoneIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
name_contact = cursor.getString(nameIndex);
num_contact = cursor.getString(phoneIndex);
}
Hospital hospital= new Hospital();
hospital.setHos_name(name_contact);
hospital.setHos_tel(num_contact);
list_hospital.add(hospital);
mAdapter.notifyItemInserted(list_hospital.size()-1);
}
EDIT: How i can use difference View in my code it mean like i feed form data use view_1 and when i add data use view_2
This Image show difference view when i add view_2 have a delete button it form ios phone
I found a few things wrong with your code. Since you have add a ValueEventListener onDataChange will be trigger everytime something happens to your mRef. That is ok. But the thing is you have set the adapter and the layout manager on that event and every time the recyclerview's adapter change when something happen to that mRef.
Here is how to do it properly.
Put the following code inside the onCreate method below add_num_call = findViewById(R.id.recycler_add_num_call); line.
add_num_call.setLayoutManager(new LinearLayoutManager(SettingActivity.this));
mAdapter = new SettingCallAdapter(SettingActivity.this , list_hospital);
mAdapter.notifyDataSetChanged();
add_num_call.setHasFixedSize(true);
Then inside onDataChange you can add the item to your adapter and notify the change like below.
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()){
Hospital mHospital = dataSnapshot1.getValue(Hospital.class);
list_hospital.add(mHospital);
}
mAdapter.notifyDataSetChanged();
As for your question, you can do this on your onActivityResult.
Hospital hospital= new Hospital();
hospital.setHos_name(name_contact);
hospital.setHos_tel(num_contact);
list_hospital.add(hospital);
mAdapter.notifyDataSetChanged();// or better to use ---> mAdapter.notifyItemInserted(list_hospita.size()-1);
Enjoy!
check whether number and name is empty or not

DiffUtil Callback with Cursor closed to early

I try the new DiffUtil to get the differences in a RecyclerView.Adapter. But the old cursor on a reload is closed before the diff can be calculated and I don't know why. This CursorCallback is the Callback base, this Adapter is my base and here is my activity code:
public class RecyclerActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{
private RecyclerView recyclerView;
private ItemAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize( true );
recyclerView.setLayoutManager(new LinearLayoutManager(this) );
recyclerView.setAdapter(adapter = new ItemAdapter(this));
recyclerView.setItemAnimator(new ItemAnimator());
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
long id = recyclerView.getAdapter().getItemId( viewHolder.getAdapterPosition() );
viewHolder.itemView.getContext().getContentResolver().delete(ContentUris.withAppendedId(CategoryContract.CONTENT_URI, id), null, null);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
getSupportLoaderManager().initLoader(0, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(this, CategoryContract.CONTENT_URI, CategoryContract.PROJECTION, null, null, CategoryContract.COLUMN_ID + " DESC");
}
public void addItem( View button ) {
int count = recyclerView != null ? recyclerView.getChildCount() : 0;
ContentValues v = new ContentValues(1);
v.put(CategoryContract.COLUMN_NAME, "Foo Nr. " + count);
getContentResolver().insert(CategoryContract.CONTENT_URI, v);
}
private Task setter;
#Override
public void onLoadFinished( final Loader<Cursor> loader, final Cursor data) {
if( setter != null) {
setter.cancel(true);
}
setter = new Task( adapter );
AsyncTaskCompat.executeParallel(setter, adapter.getCursor(), data );
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.changeCursor(null);
}
public static class Task extends AsyncTask<Cursor, Void, Pair<Cursor, DiffUtil.DiffResult>> {
private final CursorRecyclerViewAdapter adapter;
Task(CursorRecyclerViewAdapter adapter) {
this.adapter = adapter;
}
#Override
protected Pair<Cursor, DiffUtil.DiffResult> doInBackground(Cursor... params) {
return Pair.create( params[1], DiffUtil.calculateDiff( new ItemCallback( params[0], params[1]) ) );
}
#Override
protected void onPostExecute(Pair<Cursor, DiffUtil.DiffResult> diffResult) {
if( isCancelled() )
return;
adapter.swapCursor(diffResult.first);
diffResult.second.dispatchUpdatesTo(adapter);
}
}
public static class ItemAdapter extends CursorRecyclerViewAdapter<ItemHolder>
{
ItemAdapter( Context context ) {
super(context, null);
}
#Override
public void onBindViewHolder(ItemHolder viewHolder, Cursor cursor) {
CategoryModel model = CategoryModel.FACTORY.createFromCursor( cursor );
viewHolder.textView.setText( model.getId() + " - " + model.getName() );
}
#Override
public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ItemHolder(LayoutInflater.from( parent.getContext() ).inflate( R.layout.item, parent, false ));
}
}
public static class ItemHolder extends RecyclerView.ViewHolder {
TextView textView;
ItemHolder(View itemView) {
super(itemView);
textView = ( TextView ) itemView.findViewById(R.id.textView);
}
}
public static class ItemCallback extends CursorCallback<Cursor> {
public ItemCallback(Cursor newCursor, Cursor oldCursor) {
super(newCursor, oldCursor);
}
#Override
public boolean areRowContentsTheSame(Cursor oldCursor, Cursor newCursor) {
CategoryModel oldCategory = CategoryModel.FACTORY.createFromCursor(oldCursor);
CategoryModel newCategory = CategoryModel.FACTORY.createFromCursor(newCursor);
return oldCategory.getName().equals( newCategory.getName() );
}
#Override
public boolean areCursorRowsTheSame(Cursor oldCursor, Cursor newCursor) {
return oldCursor.getLong(0) == newCursor.getLong(0);
}
}
}
Any help is welcome. Maybe the old cursor is closed when a new cursor with same query is returned. The cursor is open at the moment I call getCursor() in onLoadFinished() but closed inside CursorCallback on first usage.
You have encountered an expected behaviour of CursorLoader — they close the old Cursor after another one arrives, whether you are currently using it or not.
The event sequence in your case is like this:
You get the (still open) Cursor and start a diff computation in some background thread X of AsyncTask thread pool
Something somewhere calls ContentResolver.notifyChanged
The CursorLoader is loading a new Cursor in another background thread Y. That new Cursor is posted to onLoadFinished and, probably, already swapped into the list adapter.
CursorLoader closes old Cursor.
Your background thread X does not know about point 2,3 and keeps using old Cursor until it finds out that it is closed by CursorLoader. An Exception is thrown.
In order to keep using the Cursor from background thread, you will have to manually manage your Cursor (without aid of CursorLoader): close it yourself if configuration change or onDestroy happen.
Alternatively, just intercept the exception and treat it as a sign that your background diff computation is being cancelled (it will shortly be performed for another Cursor anyway).

notifyDataSetChanged() not refreshing adapter

My adapter list is refreshing on broadcast receiver .
Everything is working fine if adapter list size is greater than 1 ,
means if my recyclerview has already one row shwoing then list refreshing just fine .
But if list size goes from 0 to 1 then my adapter notify dataset
Changed stop working . No data shows on recyclerview. I don't know why it is not working .
Recyclerview Class:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.job_recyclerview, container, false);
getActivity());
initialise(v);
init();
showNoTaskMessage();
new loadListTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
mMyBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here you can refresh your listview or other UI
SlidingTab.slidingTab.getTabAt(0).setText("New (" + SingleTon.getInstance().getNewjob() + ")");
SlidingTab.slidingTab.getTabAt(1).setText("In Progress (" + SingleTon.getInstance().getInprogressjob() + ")");;
SlidingTab.slidingTab.getTabAt(2).setText("Completed (" + SingleTon.getInstance().getCompletedjob() + ")");
}
};
try {
IntentFilter filter = new IntentFilter("newJob");
LocalBroadcastManager.getInstance(context).registerReceiver(mMyBroadcastReceiver,
filter);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return v;
}
Adapter class :
public JobAdapter(ArrayList<Info> myDataset, Context context) {
this.mDataset = myDataset;
this.mAct = context;
}
public void addApplications(ArrayList<Info> candidates) {
if (this.filterList == null) {
filterList = new ArrayList<>();
}
this.mDataset.clear();
this.mDataset.addAll(candidates);
this.filterList.addAll(mDataset);
this.notifyItemRangeInserted(0, candidates.size() - 1);
}
public void clearApplications() {
int size = this.mDataset.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
mDataset.remove(0);
filterList.remove(0);
}
this.notifyItemRangeRemoved(0, size);
}
}
#Override
public int getItemViewType(int position) {
return VIEW_NORMAL;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_job_card, parent, false);
ViewHolder fh = new ViewHolder(v);
return fh;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// holder.jobPhone.setText(mDataset.get(position).mobileNo);
holder.jobNumber.setText(mDataset.get(position).jobNumber);
holder.jobTime.setText(mDataset.get(position).time);
holder.jobAddress.setText(mDataset.get(position).address);
// holder.jobInstructionText.setText(mDataset.get(position).spclInstruction);
if (mDataset.get(position).jobStatus != null && mDataset.get(position).jobStatus.equalsIgnoreCase("Completed")) {
holder.endsat.setText("Submitted at");
holder.jobTime.setText(mDataset.get(position).completedOnString);
holder.jobTimeLeft.setVisibility(View.INVISIBLE);
holder.timerImage.setVisibility(View.INVISIBLE);
} else {
if (mDataset.get(position).status.equalsIgnoreCase("Active")) {
holder.jobTimeLeft.setText(mDataset.get(position).appointmentTime);
} else {
holder.jobTimeLeft.setText("-" + mDataset.get(position).appointmentTime);
}
}
holder.jobLayout1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SingleTon.getInstance().setWorkDescHolder(mDataset.get(position).descHolder);
FragmentManager fragmentManager = ((FragmentActivity) mAct).getSupportFragmentManager();
FragmentTransaction ft = ((FragmentActivity) mAct).getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.glide_fragment_horizontal_in, R.anim.glide_fragment_horizontal_out);
ft.replace(R.id.content_frame1, new DetailsFragment(), "persondetails");
ft.addToBackStack("persondetails");
// Start the animated transition.
ft.commit();
}
});
}
#Override
public int getItemCount() {
return mDataset.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView jobNumber, jobTimeLeft, jobStatus, jobAddress, jobEmail, jobPhone, timeTimer, jobInstructionText, jobTime, endsat;
private ImageView timerImage;
private FrameLayout frameLayout;
private CardView cardView;
private LayoutRipple jobLayout1;
public ViewHolder(View v) {
super(v);
this.jobNumber = (TextView) v.findViewById(R.id.job_number);
this.jobTime = (TextView) v.findViewById(R.id.job_time);
this.jobTimeLeft = (TextView) v.findViewById(R.id.job_timertext);
this.timerImage = (ImageView) v.findViewById(R.id.timerimage);
this.cardView = (CardView) v.findViewById(R.id.card_view);
// this.jobStatus = (TextView) v.findViewById(R.id.job_status);
this.jobAddress = (TextView) v.findViewById(R.id.job_addresstext);
// this.jobInstructionText = (TextView) v.findViewById(R.id.instruction_text);
// this.jobLayout = (LayoutRipple)v.findViewById(R.id.job_cardLayout);
this.jobLayout1 = (LayoutRipple) v.findViewById(R.id.cardLayout1);
this.endsat = (AppCompatTextView) v.findViewById(R.id.endsat);
this.jobNumber.setTypeface(Utils.RegularTypeface(mAct));
this.jobAddress.setTypeface(Utils.RegularTypeface(mAct));
this.jobTimeLeft.setTypeface(Utils.RegularTypeface(mAct));
this.jobTime.setTypeface(Utils.RegularTypeface(mAct));
}
}
}
Please help me finding the bug or some other approach . Thanks
Call the data loading task inside the onReceive() of BroadcastReceiver
mMyBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here you can refresh your listview or other UI
new loadListTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
SlidingTab.slidingTab.getTabAt(0).setText("New (" + SingleTon.getInstance().getNewjob() + ")");
SlidingTab.slidingTab.getTabAt(1).setText("In Progress (" + SingleTon.getInstance().getInprogressjob() + ")");;
SlidingTab.slidingTab.getTabAt(2).setText("Completed (" + SingleTon.getInstance().getCompletedjob() + ")");
}
};
And also do following changes in your Adapter class.
public void addApplications(ArrayList<Info> candidates) {
if (this.filterList == null) {
filterList = new ArrayList<>();
}
this.mDataset.clear();
this.mDataset.addAll(candidates);
this.filterList.addAll(mDataset);
this.notifyItemRangeInserted(0, candidates.size());
}
public void clearApplications() {
int size = this.mDataset.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
mDataset.remove(i);
filterList.remove(i);
}
this.notifyItemRangeRemoved(0, size);
}
}
Hope that works!
Change this:
mMyBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here you can refresh your listview or other UI
recycleAdapter.addItems(SingleTon.getInstance()
.getInfoArrayList());
// I'm assuming your "SingleTon.getInstance().getInfoArrayList()" is the received data.
}
On your Adapter
public void addItems(List<Info> itemsList) {
// This check could be avoided if you declared your mDataset final
if(mDataset == null) {
mDataset = new ArrayList<>();
}
int prevSize = mDataset.size();
mDataset.addAll(itemsList);
notifyItemRangeInserted(prevSize, itemsList.size());
}
You shouldn't call notifyDataSetChanged() after this.notifyItemRangeInserted(0, candidates.size() - 1); try something like this:
put this method to your adapter class
public void setData(ArrayList<Info> infos) {
this.mDataset = infos;
notifyDataSetChanged();
}
and call it like this:
ArrayList<Info> list = SingleTon.getInstance().getInfoArrayList().isEmpty();
if (list != null && !list.isEmpty()) {
recycleAdapter.setData(list);
}
correct this method in your adapter
#Override
public int getItemCount() {
return mDataset != null && !mDataset.isEmpty() ? mDataset.size() : 0;
}
Base on your code, we need a variable list to store your info data.
//Declare the info list
private ArrayList<Info> mInfos = new ArrayList<Info>()
In your onCreateView(), set mInfos to your recycleAdapter
recycleAdapter = new JobAdapter(mInfos, getActivity());
recyclerView.setAdapter(recycleAdapter);
So, every time you want to set new info list. Just assign it to mInfos
and make sure, you clear your previous list data to avoid duplicate data.
mInfos.clear()
mInfos.addAll(SingleTon.getInstance().getInfoArrayList());
//refresh data
recycleAdapter.notifyDataSetChanged();
I am not sure where you are using clearApplications() in JobAdapter.class.
But, it seems to be wrong. In the for-loop, you are trying to remove the value at index 0 every time rather than index 'i'. Hope this helps.
when you are using custom adapter then notifyDatasetChange() not called from outside that adapter so make addItem function in adapter and add new List in Adapter list and call notifyDataSetChanged
public void addItem(List<Model> list) {
if (lit != null) {
clear();
adapterList.addAll(list);
}
notifyDataSetChanged();
}
Do Change In your recyclerview class.
//Change condition ">1" to "!=null"
if (SingleTon.getInstance().getInfoArrayList().size() != null) {
recycleAdapter.addApplications(SingleTon.getInstance().getInfoArrayList());
recycleAdapter.notifyDataSetChanged();
and then do change in your adapter.
public void addApplications(ArrayList<Info> candidates) {
if (this.filterList == null) {
filterList = new ArrayList<>();
}
this.mDataset.clear();
this.mDataset.addAll(candidates);
this.filterList.addAll(mDataset);
this.notifyItemRangeInserted(0, mDataset.size()); //notify to mDataset
}
hope this will work!

Sort RecyclerView

I'm using recyclerview to show my list of ground machines. Also I have a check box widget. When check box is checked, I want to sort my list by brand of machine. In my adapter I have a method setMachine(List listMachines); which has a reference to my current list of machines. Also my sort method works fine, but when I checked my check box my list is not sorted, worst it's disappeared, and my current list of machines is zero. Can someone help me to understand why that is happening:
My RecyclerView Adapter:
public class ListMachineAdapter extends RecyclerView.Adapter<ListMachineAdapter.ViewHolder> {
private List<Machine> listOfMachines;
private ClickMachineItemListener selectMachine;
private View.OnClickListener showToast = new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewHolder vh = (ViewHolder) v.getTag();
int position = vh.getItemPosition();
selectMachine.onClick(position);
}
};
public ListMachineAdapter(List<Machine> listOfMachines) {
this.listOfMachines = listOfMachines;
}
#Override
public ListMachineAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_list_machine, parent, false);
view.setOnClickListener(showToast);
return new ViewHolder(view, viewType);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Machine machine = listOfMachines.get(position);
holder.setPosition(position);
holder.brandMachine.setText(machine.getTypeBrand());
holder.typeMachine.setText(machine.getTypeMachine());
}
#Override
public int getItemCount() {
return listOfMachines.size();
}
public void setMachine(List<Machine> listMachines){
this.listOfMachines = listMachines; // size = 0 ??
}
public void setSelectMachine(ClickMachineItemListener selectMachine){
this.selectMachine = selectMachine;
}
Also I using Singleton to store my sort method:
public class MachineManager {
private static MachineManager instance;
private List<Machine> listOfGroundMachines;
private MachineManager() {
listOfGroundMachines = new ArrayList<>();
}
public static MachineManager getInstance() {
return instance = (instance == null) ? new MachineManager() : instance;
}
public List<Machine> sortByTypeBrand() {
Collections.sort(listOfGroundMachines, new Comparator<Machine>() {
#Override
public int compare(Machine lhs, Machine rhs) {
return lhs.getTypeBrand().compareToIgnoreCase(rhs.getTypeBrand());
}
});
return listOfGroundMachines;
}
}
And this is my Activity:
public class ListGroundMachineActivity extends Activity {
private CheckBox sortByTypeMachine, sortByTypeEngine, sortByTypeBrand, sortByYear;
private List<Machine> listOfGroundMachines;
private ListMachineAdapter adapter;
private MachineManager manager;
private ClickMachineItemListener click = new ClickMachineItemListener() {
#Override
public void onClick(int position) {
Machine machine = listOfGroundMachines.get(position);
Intent intent = new Intent(ListGroundMachineActivity.this, MachineDetailsActivity.class);
intent.putExtra(Constants.TYPE, machine.getTypeMachine());
intent.putExtra(Constants.BRAND, machine.getTypeBrand());
intent.putExtra(Constants.YEAR, machine.getYear());
intent.putExtra(Constants.ENGINE, machine.getTypeEngine());
Toast.makeText(ListGroundMachineActivity.this, machine.getTypeBrand(), Toast.LENGTH_SHORT).show();
startActivity(intent);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_ground_machine);
manager = MachineManager.getInstance();
listOfGroundMachines = populateGroundListMachine();
Log.i("TAG", "List size is " + listOfGroundMachines.size());
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list_ground_machine);
adapter = new ListMachineAdapter(listOfGroundMachines);
sortByTypeMachine = (CheckBox) findViewById(R.id.sort_by_type_ground_machine);
adapter.setSelectMachine(click);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(this)
.color(R.color.teal).build());
recyclerView.setAdapter(adapter);
sortByTypeMachine.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
adapter.setMachine(manager.sortByTypeBrand());
adapter.notifyDataSetChanged();
Log.i("TAG 1", "List size is " + manager.sortByTypeBrand());
}
});
}
private List<Machine> populateGroundListMachine() {
List<Machine> listOfGroundMachineOne = new ArrayList<>();
MachineDB machineDb = new MachineDB(this);
SQLiteDatabase sqLiteDatabase = machineDb.getReadableDatabase();
Cursor cursor = sqLiteDatabase.query(MachineDB.TABLE_GROUND_MACHINE, null, null, null, null, null, null);
while (cursor.moveToNext()) {
String typeBrand = cursor.getString(cursor.getColumnIndex(Constants.BRAND));
String typeMachine = cursor.getString(cursor.getColumnIndex(Constants.TYPE));
String typeEngine = cursor.getString(cursor.getColumnIndex(Constants.ENGINE));
String year = cursor.getString(cursor.getColumnIndex(Constants.YEAR));
Machine machine = new Machine(typeBrand, typeMachine, typeEngine, year);
listOfGroundMachineOne.add(machine);
}
sqLiteDatabase.close();
return listOfGroundMachineOne;
}
Your listOfGroundMachines in MachineManager is only an empty arraylist:
private MachineManager() {
listOfGroundMachines = new ArrayList<>();
}
You need to create setter for that and call the setter after this code:
manager = MachineManager.getInstance();
listOfGroundMachines = populateGroundListMachine();
// here
The MachineManager listOfGroundMachines is an empty list.
You call listOfGroundMachines = populateGroundListMachine(); in your Activity class.
The list being populated with the machines is a member of ListGroundMachineActivity and not of MachineManager.

Categories

Resources