I have a RecyclerView, long click listener on any item will open delete dialog, the delete dialog contain two buttons, delete and cancel, when clicking on delete a document in Firestore should be deleted.
Now, how can I get the path of clicked item and send it to the delete dialog?
I can't use (intent) in dialog activity!
Note: I know there is other way to make a dialog but I faced the same problem..
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_std_in_this_class);
Intent intent = getIntent();
final String MyG = intent.getStringExtra(EXTRA_MYG);
query = db.collection("aaa").document("bbb").collection("ddd")
.document(UserId).collection(MyG).whereEqualTo("f",1);
FirestoreRecyclerOptions <infoOfMyStd> options = new
FirestoreRecyclerOptions.Builder<infoOfMyStd>()
.setQuery(query, infoOfMyStd.class)
.build();
mystdsAdapter = new MyStdsAdapter(options);
mystdsAdapter.setOnItemLongClickListener(new MyStdsAdapter.OnItemLongClickListener() {
#Override
public boolean onItemLongClicked(int position, DocumentSnapshot documentSnapshot) {
infoOfMyStd infoofmystd = documentSnapshot.toObject(infoOfMyStd.class);
String path = documentSnapshot.getReference().getPath();
Intent intent = new Intent(MyStdInThisClass.this, DeleteDialog.class);
intent.putExtra(EXTRA_STD_PATH, path);
startActivity(intent);
return true;
}
});
RecyclerView recyclerView = findViewById(R.id.my_stds_recyclerview);
recyclerView.setHasFixedSize(true); //for performane reasons
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(mystdsAdapter);
mystdsAdapter.startListening();
////
}
And ViewHolder in the the adapter:
cardView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
DeleteDialog dialog = new DeleteDialog(v.getContext());
dialog.show();
return true;
}
});
Also in the Adapter:
public interface OnItemLongClickListener {
public boolean onItemLongClicked(int position, DocumentSnapshot documentSnapshot);
}
public void setOnItemLongClickListener(OnItemLongClickListener Llistener){
this.Llistener = Llistener;
}
Appreciate your help..
Related
I have apps where the requirement is update & delete the item of RecyclerView using dialog. The dialog will open after click the popup menu
I create the dialog function on Adapter class in onBindViewHolder. The function successfully update and delete the data on server. How do I refresh the RecyclerView after it?
Adapter.java
holder.cBtnMore.setOnClickListener(v -> {
PopupMenu popupMenu = new PopupMenu(v.getContext(), holder.cBtnMore);
popupMenu.getMenuInflater().inflate(R.menu.more_menu, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(menuItem -> {
if (menuItem.getItemId() == R.id.menu_update) {
final Dialog dialog = new Dialog(v.getContext());
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog_update);
dialog.getWindow().setLayout(Cons.widthScreen, Cons.heightScreen);
// Declaration & Set Text
...
btnUpdate.setOnClickListener(unused -> {
updateBarang(
v.getContext(),
id,
etNama.getText().toString(),
etAlamat.getText().toString(),
etNoPenjual.getText().toString(),
etKodeBarang.getText().toString(),
etJumlahPenjualan.getText().toString(),
etHargaSatuan.getText().toString(),
etDiskon.getText().toString(),
etTotalHarga.getText().toString()
);
});
btnCancel.setOnClickListener(unused -> {
dialog.dismiss();
});
dialog.show();
} else if (menuItem.getItemId() == R.id.menu_delete) {
Toast.makeText(v.getContext(), "Delete", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(v.getContext(), "Error", Toast.LENGTH_SHORT).show();
}
return true;
});
popupMenu.show();
});
MainActivity.java
public class MainActivity extends AppCompatActivity {
FloatingActionButton fabAdd;
RecyclerView rvBarang;
ApiInterface apiInterface;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
apiInterface = ApiConnection.Connection().create(ApiInterface.class);
...
rvBarang.setLayoutManager(new LinearLayoutManager(this));
}
#Override
protected void onResume() {
Call<List<Barang>> tampilBarang = apiInterface.listBarang();
tampilBarang.enqueue(new Callback<List<Barang>>() {
#Override
public void onResponse(Call<List<Barang>> call, Response<List<Barang>> response) {
ArrayList<Barang> barangArrayList = (ArrayList<Barang>) response.body();
BarangAdapter barangAdapter = new BarangAdapter(barangArrayList);
rvBarang.setAdapter(barangAdapter);
}
#Override
public void onFailure(Call<List<Barang>> call, Throwable t) {
// TODO
}
});
super.onResume();
}
}
If you want to update your recyclerview then you have to update your data source of adapter means list data which you are using in adapter to show and after that you need to notify adapter to refresh
To update recyclerview after delete , add below method in your adapter class
public void deleteItem(int position){
sourceList.removeAt(position); // updating source
notifyItemRemoved(position); // notify adapter to refresh
}
To refresh recyclerview after update , you must have position along with updated object so add below method also in adapter class
public void updateData(int position, Barang updatedObject){
sourceList.set(position,updatedObject); // updating source
notifyDataSetChanged(); // notify adapter to refresh
}
after adding above methods , you can just call it to refresh
I'm currently building a booking application for laundry's machine. I need to get the item count and if the count is zero it will show the dialog box which told user that there is no data in the system.
The Activity code:
public class DobbySelection2 extends AppCompatActivity {
String local;
private Dialog dialog;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private DobbyAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dobby_selection2);
dialog = new Dialog(this);
dialog.setContentView(R.layout.custom_dialog2);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
dialog.getWindow().setBackgroundDrawable(getDrawable(R.drawable.custom_dialogbackground));
}
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
dialog.setCancelable(false); //Optional
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation; //Setting the animations to dialog
Button Yes = dialog.findViewById(R.id.btn_yes);
Yes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(DobbySelection2.this, MainActivity.class );
dialog.dismiss();
startActivity(intent);
}
});
setUpRecyclerView();
}
private void setUpRecyclerView(){
Intent i = getIntent();
local = i.getStringExtra("PLACE");
if (local == null){
local = "Selangor";
}
CollectionReference dobbyRef = db.collection("locality")
.document(local)
.collection("Dobby");
Query query = dobbyRef.orderBy("name", Query.Direction.DESCENDING);
FirestoreRecyclerOptions<Dobby> options = new FirestoreRecyclerOptions.Builder<Dobby>()
.setQuery(query, Dobby.class)
.build();
adapter = new DobbyAdapter(options);
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
//recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setLayoutManager(new CustomLinearLayoutManager(this));
recyclerView.setAdapter(adapter);
if(adapter.getItemCount() == 0){
dialog.show();
}
adapter.setOnItemClickListener(new DobbyAdapter.OnItemClickListener() {
#Override
public void onItemClick(DocumentSnapshot documentSnapshot, int position) {
Dobby dobby = documentSnapshot.toObject(Dobby.class);
String id = documentSnapshot.getId();
Toast.makeText(DobbySelection2.this, "ID : " + id, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(DobbySelection2.this, Booking2.class);
intent.putExtra("PLACE", local);
intent.putExtra("ID", id);
startActivity(intent);
}
});
}
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}
}
Adapter code:
public class DobbyAdapter extends FirestoreRecyclerAdapter<Dobby, DobbyAdapter.DobbyHolder>{
private OnItemClickListener listener;
/**
* Create a new RecyclerView adapter that listens to a Firestore Query. See {#link
* FirestoreRecyclerOptions} for configuration options.
*
* #param options
*/
public DobbyAdapter(#NonNull FirestoreRecyclerOptions<Dobby> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull DobbyHolder holder, int position, #NonNull Dobby model) {
holder.textViewName.setText(model.getName());
holder.textViewAddress.setText(model.getAddress());
holder.textViewDistance.setText(model.getDistance());
}
#NonNull
#Override
public DobbyHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.itemdobby, parent, false);
return new DobbyHolder(v);
}
class DobbyHolder extends RecyclerView.ViewHolder{
TextView textViewName;
TextView textViewAddress;
TextView textViewDistance;
public DobbyHolder(#NonNull View itemView) {
super(itemView);
textViewName = itemView.findViewById(R.id.nameDobby);
textViewAddress = itemView.findViewById(R.id.addressDobby);
textViewDistance = itemView.findViewById(R.id.distanceDobby);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
if(position != RecyclerView.NO_POSITION && listener != null){
listener.onItemClick(getSnapshots().getSnapshot(position), position);
}
}
});
}
}
public interface OnItemClickListener {
void onItemClick(DocumentSnapshot documentSnapshot, int position);
}
public void setOnItemClickListener(OnItemClickListener listener){
this.listener = listener;
}
}
But the dialog box always pop up indicating that the count is zero even though there is data inside of the recycler view. How can I fix this?
My guess is that the dialog you're talking about comes from here:
if(adapter.getItemCount() == 0){
dialog.show();
}
If so, it makes sense that it shows up as this code runs before any data has been loaded.
Data is loaded from Firestore (and most modern cloud APIs) asynchronously, and this changes the order in which code executes. It's easiest to see this if you set breakpoint on the if line above, on adapter.startListening(); and on the first line inside your onBindViewHolder.
If you now run the code in the debugger, you'll see that it:
First hits the if(adapter.getItemCount() == 0){ line
Then adapter.startListening()`
Then gets to onBindViewHolder
So now it hopefully makes sense why your code always show the dialog: no data has been loaded yet at that point.
The solution for this is always the same: you need to make sure that the code that needs the data runs after the data has been loaded. Since you're using the FirestoreRecyclerAdapter from FirebaseUI, you can do this inside its onDataChanged method that signals that a complete snapshot was loaded (regardless of whether there was any data in that snapshot) and is shown in the documentation on data and error events.
So if you move your if check into a onDataChanged method in your DobbyAdapter, it will get called whenever the adapter has loaded a complete snapshot, and it will show the dialog when there are no items.
I would like the ViewProduct activity to show the detail of the item clicked on the recyclerView. My aim later is to change the textView to a editText to edit the products, but for now I would like it to show.
My problem is filling the textView with the data from the particular product from Firebase.
You will see there is a toast message that is commented out which works and show the position, so I know I am on the right track somehow. Now the app just crashes if I click on the item, giving error:
Unable to start activity ComponentInfo
Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
All I need now is to populate the textfields with the data from Firebase.
Here is my itemView in my RecyclerAdapter:
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
//Toast.makeText(context,"Position"+ position, Toast.LENGTH_SHORT).show();
if (position != RecyclerView.NO_POSITION && listener != null) {
//listener.onItemClick(getSnapshots().getSnapshot(position), position);
listener.onItemClick(getSnapshots().getSnapshot(position),(position));
Intent intent = new Intent(itemView.getContext(), ViewProduct.class);
intent.putExtra("product_ID:", position);
itemView.getContext().startActivity(intent);
}
}
});
And here is my ViewProduct Activity where I want to see the details:
public class ViewProduct extends AppCompatActivity {
private String edit_product_ID;
private TextView mProduct, mPrice;
private TextView mSave, mDelete;
private DatabaseReference product_ref;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_product);
product_ref = FirebaseDatabase.getInstance().getReference().child("ultra_liquors");
edit_product_ID = getIntent().getExtras().get("product_ID").toString();
//Toast.makeText(this, "The Product ID:" + edit_product_ID, Toast.LENGTH_SHORT).show();
mProduct = (TextView) findViewById(R.id.product);
mPrice = (TextView) findViewById(R.id.price);
mSave = (TextView) findViewById(R.id.save);
mDelete = (TextView) findViewById(R.id.delete);
RetrieveProductInfo();
}
private void RetrieveProductInfo() {
product_ref.child(edit_product_ID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if ((dataSnapshot.exists()) && (dataSnapshot.hasChild(edit_product_ID))) {
String product_name = dataSnapshot.child("product").getValue().toString();
String product_price = dataSnapshot.child("price").getValue().toString();
mProduct.setText(product_name);
mPrice.setText(product_price);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
The string in intent.putExtra("product_ID:", position); has a trailing colon-symbol behind it. which causes getExtras().get(...) to return null. null.toString() throws the error
Add this line with Intent
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
I think that was the issue try it and let me know!
Excuse my noobness. I just don't understand how to implement it to work with my code. What I'm doing is editing a name that's in a list view. When editing the name in "EditDeleteList" and get back to the previous activity (ListView) to see the name updated within the list view, nothing happens. I have to go out of the activity completely to see the change reflected. How do I get this to update? I implement an onActivityReult() method but then get this error message "java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference" so I removed it completely. How I could get the list view to update without getting that error message?
ListView.Java
public class ListView extends AppCompatActivity {
private static final String TAG = "ListView";
DatabaseHelper mDatabaseHelper;
Button btnAdd;
private EditText editText;
private android.widget.ListView listView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
mDatabaseHelper = new DatabaseHelper(this);
btnAdd = (Button) findViewById(R.id.btnAdd);
editText = (EditText) findViewById(R.id.editText);
listView = (android.widget.ListView) findViewById(R.id.lv);
ArrayList<String> list = getIntent().getStringArrayListExtra("myList");
android.widget.ListView lv = (android.widget.ListView) findViewById(R.id.lv);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
lv.setAdapter(adapter);
//Takes user back to the main activity
ImageView ivBack = (ImageView) findViewById(R.id.ivBackArrow);
ivBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: pressed back arrow");
Intent intent = new Intent(ListView.this, MainActivity.class);
startActivity(intent);
}
});
btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String newEntry = editText.getText().toString();
if (editText.length() != 0) {
addData(newEntry);
editText.setText("");
} else {
toastMessage("you must put something in the text field");
}
}
});
populateListView();
}
public void addData(String newEntry) {
boolean insertData = mDatabaseHelper.addData(newEntry);
if (insertData) {
toastMessage("Successfully inserted");
recreate();
} else {
toastMessage("Whoops, something went wrong");
}
}
private void toastMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
private void populateListView() {
Log.d(TAG, "populateListView: displaying data in the listview");
//get data and append to list
Cursor data = mDatabaseHelper.getData();
ArrayList<String> listData = new ArrayList<>();
while(data.moveToNext()) {
//get the value from the database in column 1
//set it to the arraylist
listData.add(data.getString(1));
}
//create arraylist and set it to the adapter
ListAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, listData);
listView.setAdapter(adapter);
//set onclick listen to edit activity
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
String name = adapterView.getItemAtPosition(position).toString();
Log.d(TAG, "onItemClick: you clicked on " + name);
Cursor data = mDatabaseHelper.getItemID(name); //get the id associated with that name
int itemID = -1;
while (data.moveToNext()) {
itemID = data.getInt(0);
}
if (itemID > -1) {
Log.d(TAG, "onItemID: the ID is: " + itemID);
Intent editScreenIntent = new Intent(ListView.this, EditDeleteList.class);
editScreenIntent.putExtra("id",itemID);
editScreenIntent.putExtra("name",name);
startActivity(editScreenIntent);
} else {
toastMessage("No ID found");
}
}
});
}
}
EditDeleteList.java
public class EditDeleteList extends AppCompatActivity {
private static final String TAG = "EditDeleteList";
DatabaseHelper mDatabaseHelper;
private ImageView ivDelete;
private ImageView ivApprove;
private EditText editHashtag;
private String selectedName;
private int selectedID;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_delete);
mDatabaseHelper = new DatabaseHelper(this);
editHashtag = (EditText) findViewById(R.id.editHashtag);
ivDelete = (ImageView) findViewById(R.id.ivDelete);
ivApprove = (ImageView) findViewById(R.id.ivApprove);
//get the intent extra from the ListView activity
final Intent receivedIntent = getIntent();
//get item ID passed as an extra
selectedID = receivedIntent.getIntExtra("id", -1);
//get name passed as an extra
selectedName = receivedIntent.getStringExtra("name");
//set text field to selected item text
editHashtag.setText(selectedName);
ivApprove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String item = editHashtag.getText().toString();
if (!item.equals(null)) {
mDatabaseHelper.updateName(item, selectedID, selectedName);
} else {
toastMessage("you must enter a #hashtag");
}
finish();
}
});
}
private void toastMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
In the EditDeleteList.java I have an onClickListener that saves the changes and goes back to the previous activity by using finish();
ivApprove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String item = editHashtag.getText().toString();
if (!item.equals(null)) {
mDatabaseHelper.updateName(item, selectedID, selectedName);
} else {
toastMessage("you must enter a #hashtag");
}
finish();
}
});
Notify the adapter in some part of the activity lifecycle.
OnCreate() should not run when you go back (this is the reason you have to completely recreate the activity to see the list updated) so you should use OnRestart/OnStart/OnResume to notify the adapter to check for new items.
Check this image
I need an answer on how to create an add button to add listview item, and a delete button to delete last added item. Look at my code. I made an add button but that item exists only for a few seconds and every time I close that page (go to other activity in usermode) it is deleted. Please let me know how can I fix this code and how can I write code for delete button. I need to know how to delete last made item. Thanks for your help in advance. I am looking forward to reply.
public class dodaj extends Activity {
ListView lv;
SearchView sv;
EditText txtinput;
ArrayList<String> arrayList;
String[] recepies={};
ArrayAdapter<String> adapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dodaj);
registerClickCallback();
lv=(ListView) findViewById(R.id.listView);
sv=(SearchView) findViewById(R.id.searchView);
txtinput=(EditText)findViewById(R.id.txtinput);
Button addbutton=(Button)findViewById(R.id.addbutton);
Button buttondel=(Button) findViewById(R.id.buttondel);
arrayList= new ArrayList<>(Arrays.asList(recepies));
addbutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick( View v ) {
String newItem=txtinput.getText().toString();
arrayList.add(newItem);
adapter.notifyDataSetChanged();
}
});
buttondel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick( View v ) {
int i = arrayList.size()-1;
arrayList.remove(arrayList.get(i));
}
});
adapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,arrayList);
lv.setAdapter(adapter);
sv.setOnQueryTextListener(new OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String text) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onQueryTextChange(String text) {
adapter.getFilter().filter(text);
return false;
}
});
}
private void registerClickCallback(){
lv=(ListView) findViewById(R.id.listView);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View viewClicked, int position, long id) {
TextView textView= (TextView) viewClicked;
if(position==0){
goToMojRecept1();
}else if(position==1){
goToMojRecept2();
}else if(position==2){
goToMojRecept3();
}else if(position==3){
goToMojRecept4();
}else if(position==4) {
goToMojRecept5();
}
}
});
}
private void goToMojRecept5() {
Intent intent = new Intent(this, MojRecept5.class);
startActivity(intent);
}
private void goToMojRecept4() {
Intent intent = new Intent(this, MojRecept4.class);
startActivity(intent);
}
private void goToMojRecept3() {
Intent intent = new Intent(this, MojRecept3.class);
startActivity(intent);
}
private void goToMojRecept2() {
Intent intent = new Intent(this, MojRecept2.class);
startActivity(intent);
}
private void goToMojRecept1() {
Intent intent = new Intent(this, MojRecept1.class);
startActivity(intent);
}