I'm facing a problem when I add values in firebase and tried to read and view these valued in tableRow using textView, but I get repeated values and when I navigate between fragments and come back to this fragment the repeated values disappear, how can I solve this problem? how can I view these values without the repeated values?
this is the code
public class RoomFragment extends Fragment {
TableLayout stk;
TableRow tbrow0;
Context thiscontext;
Button addNewRoom;
ArrayList<Rooms> rooms;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
thiscontext = container.getContext();
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_room,
container, false);
addNewRoom = (Button) rootView.findViewById(R.id.addNewRoom);
rooms = new ArrayList<Rooms>();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Add Room
addNewRoom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
updateDetail();
}
});
return rootView;
}
public void updateDetail() {
Intent intent = new Intent(getActivity(), add_room.class);
startActivity(intent);
}
#Override
//
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
addTable();
}
// This event is triggered soon after onCreateView().
// Any view setup should occur here. E.g., view lookups and attaching view listeners.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// Setup any handles to view objects here
// EditText etFoo = (EditText) view.findViewById(R.id.etFoo);
stk=(TableLayout)view.findViewById(R.id.table_main);//table layout
}
public void addTable(){
// fetch reference database
DatabaseReference mDbRef = FirebaseDatabase.getInstance().getReference().child("Rooms");
// Read from the database
mDbRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()){
// Storing DB values in class
Rooms room = ds.getValue(Rooms.class);
rooms.add(room);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Display Room numbers
String RNum = ds.child("number").getValue().toString();
TableRow tbrow=new TableRow(thiscontext);// row
TextView t2v=new TextView(thiscontext);
t2v.setText(RNum);
t2v.setPadding(0,0,30,10);
t2v.setTextColor(Color.parseColor("#2171C1"));
t2v.setGravity(Gravity.LEFT);
t2v.setTextSize(20);
tbrow.addView(t2v);
TextView t3v=new TextView(thiscontext);
t3v.setText(" ");
t3v.setPadding(30,0,30,10);
tbrow.addView(t3v);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Modify a Room
ImageView editimg = new ImageView(thiscontext);
editimg.setBackgroundResource(R.drawable.ic_edit);
editimg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//**Send Room number
Intent intent = new Intent(getActivity(), modify_room.class);
String No = ds.getKey();
intent.putExtra("No", No );
intent.putExtra("number", room.getNumber() );
intent.putExtra("employee", room.getEmployee());
intent.putExtra("status", room.getStatus());
// intent.putExtra("department", room.getDepartment());
// intent.putExtra("type", room.getType());
startActivity(intent);
}
});
tbrow.addView(editimg);
TextView t4v=new TextView(thiscontext);
t4v.setText(" ");
t4v.setPadding(30,0,30,10);
tbrow.addView(t4v);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Delete a Room
ImageView deleteimg = new ImageView(thiscontext);
deleteimg.setBackgroundResource(R.drawable.ic_delete);
deleteimg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// DatabaseReference ref =ds.getRef();
// ref.removeValue();
ds.getRef().removeValue();
stk.removeView(tbrow);
Toast.makeText(getContext(),"The Room has been deleted successfully from the system",Toast.LENGTH_LONG).show();
}
});
tbrow.addView(deleteimg);
stk.addView(tbrow);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
//Log.w(TAG, "Failed to read value.", error.toException());
}
});
}
}
You can just clear the list of rooms for each call of onDataChange() to guarantee non-duplicate values.
mDbRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
rooms.clear(); // Clearing the list
for (DataSnapshot ds : dataSnapshot.getChildren()){
// Storing DB values in class
Rooms room = ds.getValue(Rooms.class);
rooms.add(room);
// rest of code
Related
Basically the app it's just a simple to do list, but when I add new task to do, it appears on firebase, but not on my app, giving the error
"E/RecyclerView: No adapter attached; skipping layout".
I tried to fix it following the answers here on stackoverflow but none of them helped me, probably I was wrong to adapt the adjustments to my code. I'm just learning and this is my first project, I was following a tutorial to do it.
Anyway, this is the MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonadd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
Intent a = new Intent(MainActivity.this, AggiungiPiattoAttivity.class);
startActivity(a);
}
});
//working with data
ourdoes = findViewById(R.id.ourdoes);
ourdoes.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<MyDoes>();
//get data from firebase
reference = FirebaseDatabase.getInstance(URL).getReference().child("AppLista");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//set code to retrive data and replace layout
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren())
{
MyDoes p = dataSnapshot1.getValue(MyDoes.class);
list.add(p);
}
doesAdapter = new DoesAdapter(MainActivity.this, list);
ourdoes.setAdapter(doesAdapter);
doesAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
//set code to show an error
Toast.makeText(getApplicationContext(), "No Data", Toast.LENGTH_SHORT).show();
}
});
}
This is the class where I add a new to do task:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aggiungi_piatto_attivity);
buttonaddnewpiatto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//insert data to database
reference = FirebaseDatabase.getInstance(URL).getReference().child("BoxDoese").child("Does" + doesNum);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataSnapshot.getRef().child("titledoes").setValue(addnamenewpiattosetted.getText().toString());
dataSnapshot.getRef().child("descdoes").setValue(adddescnewpiattosetted.getText().toString());
dataSnapshot.getRef().child("qualcosaalpostodiunimmagine").setValue(addrecipenewpiattosetted.getText().toString());
Intent a = new Intent( AggiungiPiattoAttivity.this, MainActivity.class);
startActivity(a);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
});
This is my adapter class:
public class DoesAdapter extends RecyclerView.Adapter<DoesAdapter.MyViewHolder> {
Context context;
ArrayList<MyDoes> myDoes;
public DoesAdapter(){
}
public DoesAdapter(Context c, ArrayList<MyDoes> p ){
context = c;
myDoes=p;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_does, viewGroup, false));
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder myViewHolder, int i) {
myViewHolder.titledoes.setText(myDoes.get(i).getTitledoes());
myViewHolder.qualcosaalpostodiunimmagine.setText(myDoes.get(i).getQualcosaalpostodiunimmagine());
myViewHolder.descdoes.setText(myDoes.get(i).getDescdoes());
}
#Override
public int getItemCount() {
return myDoes.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView titledoes, descdoes, qualcosaalpostodiunimmagine;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
titledoes = (TextView) itemView.findViewById(R.id.titledoes);
qualcosaalpostodiunimmagine = (TextView) itemView.findViewById(R.id.qualcosaalpostodiunimmagine);
descdoes = (TextView) itemView.findViewById(R.id.descdoes);
}
}
}
I also have other classes but to not put too much code I avoid to put them, they should not be relevant.
Create an empty adapter the same time you set LayoutManager for the RecyclerView: Save it as field of your class:
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
doesAdapter = new DoesAdapter(MainActivity.this, list);
recyclerView.setAdapter(DoesAdapter);
When data is ready, populate the adapter and notify:
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
/// origin code here
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren())
{
MyDoes p = dataSnapshot1.getValue(MyDoes.class);
list.add(p);
}
// reset data in adapter and not re-creating adapter:
doesAdapter.setItems(list);
doesAdapter.notifyDataSetChanged();
// instead of doesAdapter = new DoesAdapter(MainActivity.this, list);
recyclerView.setAdapter(DoesAdapter);
}
Source: https://stackoverflow.com/a/58251986/12596713
In my app, I have an activity that displays an ArrayList of students in a RecyclerView. The students are stored in Firebase Realtime Database. The user can add or delete students. When a user deletes a student, the RecyclerView updates and shows the remaining students.
But I have a problem. For example, say I had 5 students. I want to delete all 5 so I delete them one by one. 4 of the students delete correctly and the RecyclerView updates and reflects this. It's only when I delete the last student the RecyclerView doesn't update and the student CardView stays there. I get a toast message confirming the student's deletion and I can see they have been deleted in the database. If I navigate back to the dashboard and go back into the student list, the CardView then disappears. Strange.
I've tried calling onStart again after each deletion but this hasn't helped. Any ideas?
My activity:
public class StudentListActivity extends AppCompatActivity {
//firebase auth
private FirebaseAuth mAuth;
//public variables
public String currentUserAccount;
public String teacherAccountNav = "Teacher";
public String currentUserId;
//recyclerView variables
DatabaseReference ref;
ArrayList<Student> list;
RecyclerView recyclerView;
SearchView searchView;
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_student_list);
//get current user
mAuth = FirebaseAuth.getInstance();
FirebaseUser user = mAuth.getCurrentUser();
//assert current user is not null and get current users id
assert user != null;
currentUserId = user.getUid();
//getting firebase reference of current users students
ref = FirebaseDatabase.getInstance().getReference().child("students").child(currentUserId);
//initialise views
recyclerView = findViewById(R.id.rv);
recyclerView.setHasFixedSize(true);
searchView = findViewById(R.id.searchView);
}
#Override
protected void onStart() {
super.onStart();
if(ref != null){
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//add students from firebase to an array list
if(dataSnapshot.exists()){
list = new ArrayList<>();
for(DataSnapshot ds : dataSnapshot.getChildren()){
list.add(ds.getValue(Student.class));
}
//sort by name
Collections.sort(list, Student.myName);
//make recycler view
recyclerView.setLayoutManager(new LinearLayoutManager(StudentListActivity.this));
StudentAdapterClass studentAdapterClass = new StudentAdapterClass(list);
recyclerView.setAdapter(studentAdapterClass);
//click listeners for buttons
studentAdapterClass.setOnItemClickListener(new StudentAdapterClass.OnItemClickListener() {
#Override
public void onUpdateClick(int position) {
//handle update click in here
Student student = list.get(position);
//show update dialog here
showUpdateDialog(student.getStudentId(), student.getStudentName(), student.getStudentEmail());
}
#Override
public void onDeleteClick(int position){
//handle delete click in here
Student student = list.get(position);
//show delete dialog here
showDeleteDialog(student.getStudentId());
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(StudentListActivity.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}//if
}
//dialog box for deleting student
private void showDeleteDialog(final String studentId){
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
LayoutInflater inflater = getLayoutInflater();
//dialog XML
final View dialogView = inflater.inflate(R.layout.delete_student_dialog, null);
dialogBuilder.setView(dialogView);
final ImageButton buttonNo = dialogView.findViewById(R.id.imageButtonNo);
final ImageButton buttonYes = dialogView.findViewById(R.id.imageButtonYes);
final AlertDialog alertDialog = dialogBuilder.create();
alertDialog.show();
buttonNo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
alertDialog.dismiss();
}
});
buttonYes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
deleteStudent(studentId);
alertDialog.dismiss();
}
});
}
//delete student method
private void deleteStudent(String id){
//get current user
mAuth = FirebaseAuth.getInstance();
FirebaseUser user = mAuth.getCurrentUser();
//assert current user is not null and get current users id
assert user != null;
currentUserId = user.getUid();
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("students").child(currentUserId).child(id);
databaseReference.removeValue();
Toast.makeText(this, "Student Deleted", Toast.LENGTH_LONG).show();
//clear and get new list
onStart();
}
My adapter:
public class StudentAdapterClass extends RecyclerView.Adapter<StudentAdapterClass.MyViewHolder> {
private ArrayList<Student> list;
private OnItemClickListener mListener;
public interface OnItemClickListener{
//click method for update button
void onUpdateClick(int position);
//click method for delete button
void onDeleteClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener){
mListener = listener;
}
public StudentAdapterClass(ArrayList<Student> list){
this.list = list;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_holder, viewGroup, false);
return new MyViewHolder(view, mListener);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder myViewHolder, int i) {
myViewHolder.name.setText(list.get(i).getStudentName());
myViewHolder.email.setText(list.get(i).getStudentEmail());
}
#Override
public int getItemCount() {
return list.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView name, email;
ImageButton update, delete;
MyViewHolder(#NonNull View itemView, final OnItemClickListener listener) {
super(itemView);
name = itemView.findViewById(R.id.studentName);
email = itemView.findViewById(R.id.studentEmail);
update = itemView.findViewById(R.id.updateButton);
delete = itemView.findViewById(R.id.deleteButton);
//update click listener
update.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null){
int position = getAdapterPosition();
if(position != RecyclerView.NO_POSITION){
listener.onUpdateClick(position);
}
}
}
});
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null){
int position = getAdapterPosition();
if(position != RecyclerView.NO_POSITION){
listener.onDeleteClick(position);
}
}
}
});
}
}
Every time RecyclerView data changed, you have to call the adapter method notifyDataSetChanged(), otherwise, RecyclerView cannot refresh correctly.
You can call it inside deleteStudent() method like this.
recyclerView.getAdapter().notifyDataSetChanged()
This issue is driving me crazy. I've tried 20 different things by now. So let's see if someone here can help me.
I am making a ToDo list APP using RecyclerView that stores the data in Firebase.
The app has a TasksActivity where all the tasks appear in the RecyclerView. I have a button that goes to a Task Creation dialogue. And I can create tasks, they appear then in the RecyclerView (Tasks Activity) and are updated in the firebase with no issue. I can close the APP and come back later and everything works well, all the entries appear in the app again when I load it. I can also swipe to delete an entry, and the entry also gets eliminated from the Database in firebase.
The problem, is when I create a TASK and without closing the app, I try to delete the task that I just created. It doesn't allow me to do that. When I create a new task, and instantly delete it before closing the app, it appears again. But If I then close the app, and load it again, that entry can be deleted normally, but if I am in the same session in which I created the entry there's no way I can delete it.
I was using some Log.d arguments to see how it changes. I think for various reasons that the problem is OnDataChange(). But so far I haven't been able to come to the root of the issue. This is the TaskActivity class, and after this I will paste the TasksCreation (I don't think pasting the Adapter is necessary).
public class TasksActivity extends AppCompatActivity {
DatabaseReference reference;
RecyclerView myTasks;
ArrayList<TaskItems> myTasksList;
TasksAdapter tasksAdapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tasks);
myTasks = findViewById(R.id.my_tasks); // RecyclerView that I defined as part of the layout. This is the id of it
myTasks.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
myTasksList = new ArrayList<>();
Button openCreateTask = findViewById(R.id.openCreateTask);
tasksAdapter = new TasksAdapter(this,myTasksList);
myTasks.setAdapter(tasksAdapter);
new ItemTouchHelper(itemTouchHelper).attachToRecyclerView(myTasks);
openCreateTask.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent_task = new Intent(getApplicationContext(), TasksCreation.class);
startActivity(intent_task);
}
});
reference = FirebaseDatabase.getInstance().getReference().child("MotApp"); // Name of the App in the database .child("MotApp")
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) { // It gets the info from the database
Log.d("data Changed called", "onDataChange: is called");
Log.d("whatever", "onDataChange BEGIN Array of myTasksList size is "+myTasksList.size());
myTasksList.clear(); // Added later to avoid duplication
for(DataSnapshot elements: dataSnapshot.getChildren()){
TaskItems p = elements.getValue(TaskItems.class);
myTasksList.add(p);
}
tasksAdapter.notifyDataSetChanged(); // If this is put outside of onDataChange, it displays a blank list.
Log.d("whatever", "onDataChange END Array of myTasksList size is "+myTasksList.size());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(getApplicationContext(), "No data", Toast.LENGTH_SHORT).show();
}
});
}
ItemTouchHelper.SimpleCallback itemTouchHelper = new ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
Log.d("ARRAY SIZE", "onSwiped BEGIN Array of myTasksList size is "+myTasksList.size());
String key = myTasksList.get(position).getKey();
reference= FirebaseDatabase.getInstance().getReference().child("MotApp").child(key);
Toast.makeText(getApplicationContext(),"This is key "+key,Toast.LENGTH_LONG).show();
reference.removeValue();
myTasksList.remove(position);
tasksAdapter.notifyItemRemoved(position);
Log.d("ARRAY SIZE", "onSwiped END Array of myTasksList size is "+myTasksList.size());
}
};
}
And this is for TasksCreation Activity:
public class TasksCreation extends AppCompatActivity {
DatabaseReference referenceCreation;
ArrayList<String> list;
EditText taskName;
EditText taskDescr;
Button selectDates;
TextView taskDate;
Button createTask;
Button cancel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tasks_creation);
taskName = findViewById(R.id.et_TaskName);
taskDescr = findViewById(R.id.et_TaskDescr);
selectDates = findViewById(R.id.selectDates);
taskDate= findViewById(R.id.tv_Dates);
createTask = findViewById(R.id.createTask);
cancel = findViewById(R.id.cancelButton);
createTask.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!TextUtils.isEmpty(taskName.getText()) && !TextUtils.isEmpty(taskDate.getText())) {
referenceCreation = FirebaseDatabase.getInstance().getReference().child("MotApp").push(); //saves it with custom key created by Firebase
final String key = referenceCreation.getKey();
referenceCreation.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataSnapshot.getRef().child("key").setValue(key);
dataSnapshot.getRef().child("taskTitle").setValue(taskName.getText().toString());
dataSnapshot.getRef().child("taskDescription").setValue(taskDescr.getText().toString());
dataSnapshot.getRef().child("taskDate").setValue(taskDate.getText().toString());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Intent intent = new Intent(getApplicationContext(), TasksActivity.class);
startActivity(intent);
} else{
Toast.makeText(getApplicationContext(), "You haven't filled all the fields", Toast.LENGTH_SHORT).show();
}
}
});
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), TasksActivity.class);
startActivity(intent);
}
});
selectDates.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
createAlertDialogue();
}
});
}
private void createAlertDialogue(){
list = new ArrayList<String>();
AlertDialog.Builder builder = new AlertDialog.Builder(this,R.style.MyDialogTheme);
builder.setTitle("Select days");
builder.setMultiChoiceItems(R.array.Days, null, new DialogInterface.OnMultiChoiceClickListener() {
#Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
String arr[] = getResources().getStringArray(R.array.Days);
if(isChecked){
list.add(arr[which]);
}else if(list.contains(arr[which])){
list.remove(arr[which]);
}
}
});
builder.setPositiveButton("Save", new DialogInterface.OnClickListener() {
String data = "";
#Override
public void onClick(DialogInterface dialog, int which) {
for(String elements: list){
elements = elements.substring(0,3);
data= elements+" "+data;
}
taskDate.setText(data);
}
});
builder.create();
builder.show();
}
}
I really appreciate any light to the issue.
Thanks a lot
P:S: This is the code for the TaskAdapter (Ignore the dayoftheweek part is just for a part of the code that I commented )
public class TasksAdapter extends RecyclerView.Adapter<TasksAdapter.MyViewHolder> { // V 1.3 added OnClickListener
Context context;
ArrayList<TaskItems> tasks;
DatabaseReference reference;
SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
Date d = new Date();
final String dayOfTheWeek = sdf.format(d).substring(0,3);
public TasksAdapter(Context context, ArrayList<TaskItems> tasks) {
this.context = context;
this.tasks = tasks;
}
public class MyViewHolder extends RecyclerView.ViewHolder { // V1.3 Added implements View.OnClickListener
TextView taskTitle;
TextView taskDate;
TextView taskDescription;
CheckBox taskCheckBox;
ConstraintLayout constraintLayout; // Added to change background of each RecyclerView item.
public MyViewHolder(#NonNull View itemView) {
super(itemView);
taskTitle = itemView.findViewById(R.id.taskTitle);
taskDate = itemView.findViewById(R.id.taskDate);
taskDescription = itemView.findViewById(R.id.taskDescription);
taskCheckBox = itemView.findViewById(R.id.taskCheckBox);
constraintLayout = (ConstraintLayout) itemView.findViewById(R.id.item_task_layout);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int pos = getAdapterPosition();
// if(pos != RecyclerView.NO_POSITION){//Checks if item still exists
TaskItems clickedDataItem = tasks.get(pos);
Toast.makeText(v.getContext(), "You clicked " + clickedDataItem.getTaskTitle(), Toast.LENGTH_SHORT).show();
// }
}
});
}
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) { // standard code for onCreateViewHolder
return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_task,parent,false));
}
#Override
public void onBindViewHolder(final #NonNull MyViewHolder holder, final int position) { // This method is called once for each item on the list.
holder.taskTitle.setText(tasks.get(position).getTaskTitle());
holder.taskDescription.setText(tasks.get(position).getTaskDescription());
holder.taskDate.setText(tasks.get(position).getTaskDate());
holder.taskCheckBox.setChecked(tasks.get(position).isChecked());
holder.taskCheckBox.setTag(tasks.get(position).getKey());
holder.taskCheckBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseDatabase database = FirebaseDatabase.getInstance();
String post = (String) holder.taskCheckBox.getTag();
Toast.makeText(context,"This is checkbox number: "+post,Toast.LENGTH_SHORT).show(); // Working Well. //change for new logic
reference = database.getReference("MotApp").child(post);
boolean checkboxStatus = holder.taskCheckBox.isChecked();
Log.d("Checked", "onClick: The taskcheckbox checked is "+holder.taskCheckBox.isChecked());
TaskItems value = new TaskItems(tasks.get(position).getKey(),tasks.get(position).getTaskTitle(), tasks.get(position).getTaskDate(),tasks.get(position).getTaskDescription(),checkboxStatus);
reference.setValue(value);
Toast.makeText(context,"This is a checkbox belonging to item "+tasks.get(position).getTaskTitle(),Toast.LENGTH_LONG).show();
}
});
}
#Override
public int getItemCount() { //tells the adapter the size . if it's zero then it won't create anything
return tasks.size();
}
}
You need to rebuild the RecyclerView data in your TasksActivity when you return back from the TasksCreation; that is because the onCreate() callback of the TasksActivity is called only when you open your app; and that is why the deletion works only when you close your app and reopen it.
And onCreate() is not called when you back from the the TasksCreate, because when you transfer from TasksActivity to TasksCreation, the TasksActivity is not destroyed, but just stopped, and therefore when you come back to TasksActivity it will start, and resumed; so transfer your code on the onCreate() to onResume() in order to allow the list to be updated with the recent changes.
So change your TasksActivity to the below
public class TasksActivity extends AppCompatActivity {
DatabaseReference reference;
RecyclerView myTasks;
ArrayList<TaskItems> myTasksList;
TasksAdapter tasksAdapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tasks);
}
#Override
protected void onResume() {
super.onResume();
myTasks = findViewById(R.id.my_tasks); // RecyclerView that I defined as part of the layout. This is the id of it
myTasks.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
myTasksList = new ArrayList<>();
Button openCreateTask = findViewById(R.id.openCreateTask);
tasksAdapter = new TasksAdapter(this,myTasksList);
myTasks.setAdapter(tasksAdapter);
new ItemTouchHelper(itemTouchHelper).attachToRecyclerView(myTasks);
openCreateTask.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent_task = new Intent(getApplicationContext(), TasksCreation.class);
startActivity(intent_task);
}
});
reference = FirebaseDatabase.getInstance().getReference().child("MotApp"); // Name of the App in the database .child("MotApp")
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) { // It gets the info from the database
Log.d("data Changed called", "onDataChange: is called");
Log.d("whatever", "onDataChange BEGIN Array of myTasksList size is "+myTasksList.size());
myTasksList.clear(); // Added later to avoid duplication
for(DataSnapshot elements: dataSnapshot.getChildren()){
TaskItems p = elements.getValue(TaskItems.class);
myTasksList.add(p);
}
tasksAdapter.notifyDataSetChanged(); // If this is put outside of onDataChange, it displays a blank list.
Log.d("whatever", "onDataChange END Array of myTasksList size is "+myTasksList.size());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(getApplicationContext(), "No data", Toast.LENGTH_SHORT).show();
}
});
}
ItemTouchHelper.SimpleCallback itemTouchHelper = new ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
Log.d("ARRAY SIZE", "onSwiped BEGIN Array of myTasksList size is "+myTasksList.size());
String key = myTasksList.get(position).getKey();
reference= FirebaseDatabase.getInstance().getReference().child("MotApp").child(key);
Toast.makeText(getApplicationContext(),"This is key "+key,Toast.LENGTH_LONG).show();
reference.removeValue();
myTasksList.remove(position);
tasksAdapter.notifyItemRemoved(position);
Log.d("ARRAY SIZE", "onSwiped END Array of myTasksList size is "+myTasksList.size());
}
};
}
I finally found how to solve this.
First I changed all addValueEventListener with addListenerforSingleValueEvent in TaskActivity and TaskCreation. With addValueEventListener I realized that it was making several loops everytime a new task was created which caused all kind of problems.
And I also changed the way the startIntent was set up in TaskCreation. I had set it up initially after the Listener block. But the asynchronous nature of onDataChange was making that everytime I loaded the intent the updated information wasn't set up with the new task that was just added.
By putting it inside the onDataChange it was solved. I have made several tests and now it's working flawlessly.
I wasted many days trying to solve this. But I learned a lot of lessons in the process. So I guess they weren't wasted days :) .
Thanks to all who chipped in to help me with this issue.
I'm trying to upload some data to my firebase realtime database, but everytime I start the app, the data resets and my database is empty. Why is this?
This is all done within a fragment.
I've also created a POJO Months class and a MonthList class for the listView/
Below is all of the code concerning firebase.
DatabaseReference databaseReference;
EditText editText;
public void addMonth(){
String id = databaseReference.getKey();
String name = editText.getText().toString();
boolean ifPaid = true;
Months months = new Months(name, id, ifPaid);
databaseReference.push().setValue(months);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragment_to_do,container,false);
setHasOptionsMenu(true);
final ListView listView = v.findViewById(R.id.listView);
databaseReference = FirebaseDatabase.getInstance().getReference("month");
editText = v.findViewById(R.id.editText);
monthsList = new ArrayList<>();
//button that triggers addMonth() method.
Button upload = v.findViewById(R.id.upload);
upload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addMonth();
}
});
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
monthsList.clear();
for (DataSnapshot monthsSnapshot : dataSnapshot.getChildren()){
Months months = monthsSnapshot.getValue(Months.class);
monthsList.add(months);
}
MonthList adapter = new MonthList(getActivity(), monthsList);
listView.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
return v;
}
I've created a firebase search query and it works perfectly.But now I can't seem to figure out how to do the onlick and get item position. Below is my firebase search activity:
mUserDatabase=FirebaseDatabase.getInstance().getReference("Users").child("UserProfile";
mSearchField = findViewById(R.id.search_field);
mSearchBtn = findViewById(R.id.search_btn);
mResultList = findViewById(R.id.result_list);
mResultList.setHasFixedSize(true);
mResultList.setLayoutManager(new LinearLayoutManager(this));
mSearchBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String searchText = mSearchField.getText().toString();
firebaseUserSearch(searchText);
}
});
}
private void firebaseUserSearch(String searchText) {
Toast.makeText(SearchActivity.this, "Searching......", Toast.LENGTH_LONG).show();
Query firebaseSearchQuery = mUserDatabase.orderByChild("profession").startAt(searchText).endAt(searchText + "\uf8ff");
FirebaseRecyclerAdapter<Users, UsersViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Users, UsersViewHolder>(
Users.class,
R.layout.search_list_layout,
UsersViewHolder.class,
firebaseSearchQuery
) {
#Override
protected void populateViewHolder(UsersViewHolder viewHolder, Users model, int position) {
viewHolder.setDetails(getApplicationContext(), model.getUsername(), model.getSummary(), model.getImageurl());
}
};
mResultList.setAdapter(firebaseRecyclerAdapter);
}
public static class UsersViewHolder extends RecyclerView.ViewHolder {
View mView;
private TextView user_name;
private TextView user_summary;
private ImageView user_image;
public UsersViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void setDetails(Context ctx, String userName,String userSummary,String userImage){
user_name = mView.findViewById(R.id.name_text);
user_summary = mView.findViewById(R.id.summary_text);
user_image = mView.findViewById(R.id.profile_image);
user_name.setText(userName);
user_summary.setText(userSummary);
Glide.with(ctx).load(userImage).into(user_image);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int pos = getAdapterPosition();
Snackbar.make(v, "Hello,How may i help you", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
});
}
How do i go about displaying the content in a details activity when a single item from the search result is clicked.
Based on Parag Pawar's suggestion, I tried the following, but it's not working>
#Override
protected void populateViewHolder(UsersViewHolder viewHolder, Users model, int position) {
viewHolder.setDetails(getApplicationContext(), model.getUsername(), model.getSummary(), model.getImageurl());
final String each_key = getRef(position).getKey();
}
};
Then in my UserViewHolder i initialized the onclick:
mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent pDetail = new Intent(SearchActivity.this, ProfileDetail.class);
Users each_key = each_key.get(getAdapterPosition());
pDetail.putExtra(ProfileDetail.EXTRA_POSITION, each_key.getUserId());
startActivity(pDetail);
}
});
But I am getting the error variable each_key might not have been initialized
Fixed my mistake according top advice from Parag Pawar and implemented he onclick inside populateView`holder as follows:
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/*Here use intent.putExtra() to send each_key on other activity and fetch data there*/
Toast.makeText(SearchActivity.this, "u clicked......" +position, Toast.LENGTH_LONG).show();
Intent each_key = new Intent(SearchActivity.this, ProfileDetail.class);
Users user = mResultList.get(position);
each_key.putExtra(ProfileDetail.EXTRA_POSITION, user.getUserId());
startActivity(each_key);
} });
but I am getting the error here:
Users user = mResultList.get(position);
Cannot resolve method 'get(int)'
mReultList is the name of my Recyclerview and I initialized it as follows:
private RecyclerView mResultList;
but I don't know if I'm doing this correctly. I know I am supposed to attach the results to an adapter, but I don't know how to do that. So I tried:
listItems = new ArrayList<>();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<UsersList>(listItems,this);
But this doesn't seem to work either
Updated Code
I created an array:
private List<UsersList> listItems;//UsersList is my modal class
Then added it to my onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
listItems = new ArrayList<>();
I then Implemented putExtra as follows using this array as follows:
Intent each_key = new Intent(TestSearch.this, ProfileDetail.class);
UsersList user = listItems.get(position);
//Here use intent.putExtra() to send each_key on other activity and fetch data there
Toast.makeText(TestSearch.this, "u clicked......" +position, Toast.LENGTH_LONG).show();
each_key.putExtra(ProfileDetail.EXTRA_POSITION, user.getUserId());
startActivity(each_key);
But getting this error when i click an item:
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.get(ArrayList.java:411)
at com.ecard.ecard.search.TestSearch$2$1.onClick(TestSearch.java:94)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
To get key from each item, in populateViewholder do
Example :-
final String each_key = getRef(position).getKey();
To set Click Listeners on each item, in populateViewholder do
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/*Here use intent.putExtra() to send each_key on other activity and fetch data there*/
} }); }
In the activity that contains your current
items that you want to click on:
Create a String to reference from in your populateVieHolder:
final String single_view = getRef(position).getKey();
Then attach an onclick to your ViewHolder:
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
And in your OnClick place your intents and putExtras:
#Override
public void onClick(View view) {
//give your intent a name to reference from("moreDetail" in this case)
Intent moreDetail = new Intent(SearchActivity.this,MoreDetail.class);
//attach the intent reference to access each item and key
moreDetail.putExtra(MoreDetail.EXTRA_POSITION,single_view);
startActivity(moreDetail);//Start the new activity
Then in your more details activity:
Add the ExtraPosition String
String single_view = getIntent().getExtras().getString(MoreDetail.EXTRA_POSITION);//get extra position reference previous view
From here on,you need to display your data from firebase
For accessing Single Values from Firebase
firebaseRef.child(single_view).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//For single items
// for example:String user_name = (String) dataSnapshot.child("username").getValue();
Or
For accessing Values attached to your adapter using a Listview
firebaseRef.child(single_view).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ListItem data = dataSnapshot.getValue(ListItem.class);
listItems.add(data);
adapter.notifyDataSetChanged();
//if you are accessing your data from a ListView
There are so many ways to do this.Another way to accomplish this is to create an interface.declare an onclick listener and contex in your recycler adapter:
OnItemClickListener callback;
private Context mContext;
Then implement an Onclick listener to your view holder
public static class UsersViewHolder extends RecyclerView.ViewHolder implements OnItemClickListener {
add an onclick to access a position,to your View Holder using callback:
#Override
public void onClick(View v) {
callback.onItemClick(getAdapterPosition());
}
Then create an interface:
public interface OnItemClickListener {
void onItemClick(int pos);
}
Based on your context:
In your more main activity:
#Override
public void onItemClick(int pos) {
Intent pDetail = new Intent(this.getContext(), ProfileDetail.class);//get the context
ListItem listItem = listItems.get(pos);//get the position
//Then your puEtxra here followed by start activity
startActivity(pDetail);
}
And finally call EXTRA_POSITION in your detail view followed by your datasnapshots.
You can find more details from the firebase documentation and firebase quick start samples on github:
GitHub
FirebaseDocs
I said both the things go in populateViewHolder()
You are getting not initialized error because you're using each_key in the Viewholder class.
Copy this
final String each_key = getRef(position).getKey();
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/*Here use intent.putExtra() to send each_key on other activity and fetch data there*/
} }); }
and paste it in the populateViewHolder method