Firebase Realtime Database Android Example

If your mobile app needs to store data on the cloud, you can use Firebase realtime database in your app. Firebase realtime database is one of the firebase products supported by Google and is a no-SQL cloud database. The best feature of the database is that it syncs data to all clients realtime. App using Realtime database can work offline making all the features of the app available offline.

You can build various platform apps such as Android, iOS and Javascript apps and share the same instance of realtime database.

In addition to realtime database, Firebase recently introduced cloud Firestore database which is more flexible and has its own advantages.

Table of Contents

Firebase Realtime Database Setup

Below are the steps you need to follow to setup your project for using Firebase realtime database.

First create firebase project by clicking add project on the main screen of firebase console.

Select the firebase project and click add firebase to your android app, it will open a form.

Fill the form entering package name and nick name and submit the form.

In the next screen, you will see an option to download google-services.json. Download the file and save it in your android project under app directory.

Add plugin to bottom of app level build file. plugin: 'com.google.gms.google-services'

Add below library to app level build.gradle file. classpath 'com.google.gms:google-services:3.1.0'

Add realtime database library to app level build.gradle file. implementation 'com.google.firebase:firebase-database:11.6.2'

Realtime Database Data Structure

Data in realtime database is stored as JSON tree. When a data item is added to JSON tree, key of the data item becomes node. If the key is not specified, default key is used to identify the node. It is always better to create flat JSON tree as flat structure makes it easy to retrieve only required data.

Realtime Database Add Data

You can add data to real time database using DatabaseReference object which can be obtained by calling getReference method on FirebaseDatabase object which can be obtained by calling getInstance() method on FirebaseDatabase. Method getReference on FirebaseDatabase returns reference to root node of the database.

DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference();

As mentioned before, since data is stored as JSON objects in realtime database, to add data to it, first you need to specify a node name to which you want to add data to. You can specify your own node name or have real time database generate key for your node by using push method.

To add your own node name, you need to call child method on DatabaseReference object passing node name. Below examples first creates classified node first if it doesn’t exist and then a child node under classified node using passed value as node name.

dbRef.child("classified").child(adId);

To have database create unique node name, you can just call push method on DatabaseReference object as shown below.

dbRef.child("classified").push();

Then you can add elements and child nodes to nodes using Map containing key and value pairs or java objects. To add data to a node, first get DatabaseReference of the node and then call setValue passing POJO object as shown below.

dbRef.child("classified").child(cAdId) .setValue(classifiedAd)

Method setValue return Task object to which you can add listeners to know the status of operation. As shown below OnCompleteListener is added to Task object. In OnCompleteListener’s onComplete callback method, you can check the status of operation.

dbRef.child("classified").child(cAdId) .setValue(classifiedAd) .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { } else { } } });

Realtime Database Read Data

I want to mention one point again that when you read a node from the database, you’ll get all the elements and child node under the node. So it is the structure of data that you need to focus on to be able to read only the required data.

To get a node from realtime database, you need to add listeners to DatabaseReference object of the target node.

To get result only one time, you need to add ValueEventListener to DatabaseReference object by calling addListenerForSingleValueEvent method. In onDataChange method of the listener, you can get data using DataSnapshot object passed to it. By passing your POJO class to getValue method, you can get the object populated with JSON data as shown below.

dbRef.child("classified").child(adId). addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { ClassifiedAd cAd = dataSnapshot.getValue(ClassifiedAd.class); displayAdForUpdate(cAd); } @Override public void onCancelled(DatabaseError databaseError) { Log.d(TAG, "Error trying to get classified ad for update " + ""+databaseError); } });

To continuously get data change events, you need to add ValueEventListener to DatabaseReference object by calling addValueEventListener method on it. You can even just listen for child events at the location that DatabaseReference object represents by adding ChildEventListener to it.

Realtime Database Query Data

Under a node, to get all the child nodes which are having a specified element and value, first you need to define index (indexOn) in database rules using Firebase console as shown below.

{ "rules": { ".read": "auth != null", ".write": "auth != null", "classified": { ".indexOn": "category" } . . .

Then you can query by specifying the element and value using various method of DatabaseReference object. To get nodes that match to specified value, use equalTo method, to get nodes with values greater than or equal to specified value, you can use startAt method, to get nodes with values less than or equal to the specified value and you can use endAt method.

You can also limit the number of records returned using limitToFirst and limitToLast methods of DatabaseReference object. You can sort results using orderByKey, orderByValue and orderByChild methods of DatabaseReference object.

Below code shows how to get a list of objects with an element whose value matches to the passed value.

dbRef.child("classified").orderByChild("category") .equalTo(category).addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { List<ClassifiedAd> adsList = new ArrayList<ClassifiedAd>(); for (DataSnapshot adSnapshot: dataSnapshot.getChildren()) { adsList.add(adSnapshot.getValue(ClassifiedAd.class)); } Log.d(TAG, "no of records of the search is "+adsList.size()); } @Override public void onCancelled(DatabaseError databaseError) { Log.d(TAG, "Error trying to get classified ads for " +category+ " "+databaseError); } });

You can completely override data under a node by specifying node name and adding object with updated values as explain in adding data to a node section. To update specific elements of a node, you can use updateChildren method of DatabaseReference.

Realtime Database Delete Data

To delete a node from realtime database, you need to call removeValue method on DatabaseReference object as shown below. You can add listener to know the status of delete operation.

FirebaseDatabase.getInstance().getReference() .child("classified").child(adId).removeValue()

Realtime Database Transaction

Realtime database supports transactions which can be used to maintain data consistency in the case of data that is updated concurrently. To start a transaction, you need to call runTransaction method on DatabaseReference object which represents the target node. You need to pass Transaction.Handler to runTransaction method to define operations that need to be performed by providing implementation for doTransaction and onComplete methods.

The data under the node that DatabaseReference object represents is passed to doTransaction in MutableData object. The data in the MutableData object can updated in doTransaction method. The method should return Transaction.Result object which can be obtained by calling Transaction.success object passing updated MutableData object.

If the target data is already updated, server returns the current value and client runs the transaction again with the current value.

Below example shows how to use transaction using a counter field read and write.

final DatabaseReference idDatabaseRef = FirebaseDatabase.getInstance() .getReference("ClassifiedIDs").child("id"); idDatabaseRef.runTransaction(new Transaction.Handler() { @Override public Transaction.Result doTransaction(MutableData mutableData) { if (mutableData.getValue(int.class) == null) { idDatabaseRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if(dataSnapshot != null && dataSnapshot.getValue() == null){ idDatabaseRef.setValue(1) } } @Override public void onCancelled(DatabaseError databaseError) { } }); return Transaction.abort(); } nextClassifiedID = mutableData.getValue(int.class); mutableData.setValue(nextClassifiedID + 1); return Transaction.success(mutableData); }

Realtime Database Data Security

By default, database access is restricted to authenticated users. You can add security rules and other rules to define authentication and authorization in firebase console. For more information on security and rules, read firebase realtime database rules.

For more information on firebase authentication, please read tutorial on how to implement firebase authentication and allow authenticated users to access restricted data.

Realtime Database Android Example

I’ll show how to use realtime database in android apps with an example. The example app allows user to post, view, update and delete classified ads. It uses fragments to provide add, update and view screens. It uses recycler view to display list of ads.

Add screen

Search screen

View data screen

Update screen

Activity

public class ClassifiedsActivity extends AppCompatActivity { private FragmentManager fm; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.classifieds_layout); Toolbar tb = findViewById(R.id.toolbar); setSupportActionBar(tb); tb.setSubtitle("Realtime Database"); fm = getSupportFragmentManager(); addClassifiedAdFrgmt(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.ads_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.add_ad_m: addClassifiedAdFrgmt(); return true; case R.id.view_ads_m: viewlassifiedAdFrgmt(); return true; default: return super.onOptionsItemSelected(item); } } public void addClassifiedAdFrgmt(){ FragmentTransaction ft = fm.beginTransaction(); ft.replace(R.id.adds_frame, new AddClassifiedFragment()); ft.commit(); } public void viewlassifiedAdFrgmt(){ FragmentTransaction ft = fm.beginTransaction(); ft.replace(R.id.adds_frame, new ViewClassifiedFragment()); ft.commit(); } }

Activity Layout

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="zoftino.com.firebase.realtimedb.ClassifiedsActivity"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" /> <FrameLayout android:id="@+id/adds_frame" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:layout_marginLeft="8dp" android:layout_marginStart="8dp"/> </LinearLayout>

Add Fragment

public class AddClassifiedFragment extends Fragment { private static final String TAG = "AddAdFragment"; private DatabaseReference dbRef; private int nextClassifiedID; private boolean isEdit; private String adId; private Button button; private TextView headTxt; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.ad_add_layout, container, false); button = (Button) view.findViewById(R.id.post_add); headTxt = view.findViewById(R.id.add_head_tv); dbRef = FirebaseDatabase.getInstance().getReference(); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!isEdit) { addEvent(); } else { updateEvent(); } } }); //add or update depending on existence of adId in arguments if (getArguments() != null) { adId = getArguments().getString("adId"); } if (adId != null) { populateUpdateAd(); } return view; } @Override public void onAttach(Context context) { super.onAttach(context); } public void addEvent() { ClassifiedAd classifiedAd = createClassifiedAdObj(); addClassifiedToDB(classifiedAd); } public void updateEvent() { ClassifiedAd classifiedAd = createClassifiedAdObj(); updateClassifiedToDB(classifiedAd); } private void addClassifiedToDB(final ClassifiedAd classifiedAd) { final DatabaseReference idDatabaseRef = FirebaseDatabase.getInstance() .getReference("ClassifiedIDs").child("id"); idDatabaseRef.runTransaction(new Transaction.Handler() { @Override public Transaction.Result doTransaction(MutableData mutableData) { //create id node if it doesn't exist //this code runs only once if (mutableData.getValue(int.class) == null) { idDatabaseRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { //set initial value if(dataSnapshot != null && dataSnapshot.getValue() == null){ idDatabaseRef.setValue(1); Log.d(TAG, "Initial id is set"); } } @Override public void onCancelled(DatabaseError databaseError) { } }); Log.d(TAG, "Classified id null so " + " transaction aborted, " ); return Transaction.abort(); } nextClassifiedID = mutableData.getValue(int.class); mutableData.setValue(nextClassifiedID + 1); return Transaction.success(mutableData); } @Override public void onComplete(DatabaseError databaseError, boolean state, DataSnapshot dataSnapshot) { if (state) { Log.d(TAG, "Classified id retrieved "); addClassified(classifiedAd, ""+nextClassifiedID); } else { Log.d(TAG, "Classified id retrieval unsuccessful " + databaseError); Toast.makeText(getActivity(), "There is a problem, please submit ad post again", Toast.LENGTH_SHORT).show(); } } }); } private void addClassified(ClassifiedAd classifiedAd, String cAdId) { classifiedAd.setAdId(cAdId); dbRef.child("classified").child(cAdId) .setValue(classifiedAd) .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { if(isEdit){ addClassifieds(); }else{ restUi(); } Log.d(TAG, "Classified has been added to db"); Toast.makeText(getActivity(), "Classified has been posted", Toast.LENGTH_SHORT).show(); } else { Log.d(TAG, "Classified couldn't be added to db"); Toast.makeText(getActivity(), "Classified could not be added", Toast.LENGTH_SHORT).show(); } } }); } private void populateUpdateAd() { headTxt.setText("Edit Ad"); button.setText("Edit Ad"); isEdit = true; dbRef.child("classified").child(adId). addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { ClassifiedAd cAd = dataSnapshot.getValue(ClassifiedAd.class); displayAdForUpdate(cAd); } @Override public void onCancelled(DatabaseError databaseError) { Log.d(TAG, "Error trying to get classified ad for update " + ""+databaseError); Toast.makeText(getActivity(), "Please try classified edit action again", Toast.LENGTH_SHORT).show(); } }); } private void displayAdForUpdate(ClassifiedAd cAd){ ((EditText) getActivity() .findViewById(R.id.title_a)).setText(cAd.getTitle()); ((EditText) getActivity() .findViewById(R.id.category_a)).setText(cAd.getCategory()); ((EditText) getActivity() .findViewById(R.id.desc_a)).setText(cAd.getDescription()); ((EditText) getActivity() .findViewById(R.id.name_a)).setText(cAd.getName()); ((EditText) getActivity() .findViewById(R.id.phone_a)).setText(cAd.getPhone()); ((EditText) getActivity() .findViewById(R.id.city_a)).setText(cAd.getCity()); } private void updateClassifiedToDB(ClassifiedAd classifiedAd) { addClassified(classifiedAd, adId); } private ClassifiedAd createClassifiedAdObj() { final ClassifiedAd ad = new ClassifiedAd(); ad.setTitle(((EditText) getActivity() .findViewById(R.id.title_a)).getText().toString()); ad.setCategory(((EditText) getActivity() .findViewById(R.id.category_a)).getText().toString()); ad.setDescription(((EditText) getActivity() .findViewById(R.id.desc_a)).getText().toString()); ad.setName(((EditText) getActivity() .findViewById(R.id.name_a)).getText().toString()); ad.setPhone(((EditText) getActivity() .findViewById(R.id.phone_a)).getText().toString()); ad.setCity(((EditText) getActivity() .findViewById(R.id.city_a)).getText().toString()); return ad; } private void restUi() { ((EditText) getActivity() .findViewById(R.id.title_a)).setText(""); ((EditText) getActivity() .findViewById(R.id.category_a)).setText(""); ((EditText) getActivity() .findViewById(R.id.desc_a)).setText(""); ((EditText) getActivity() .findViewById(R.id.name_a)).setText(""); ((EditText) getActivity() .findViewById(R.id.phone_a)).setText(""); ((EditText) getActivity() .findViewById(R.id.city_a)).setText(""); } private void addClassifieds() { Intent i = new Intent(); i.setClass(getActivity(), ClassifiedsActivity.class); startActivity(i); } }

Add Fragment Layout

<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="zoftino.com.firebase.realtimedb.ClassifiedsActivity"> <TextView android:id="@+id/add_head_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:text="Post Classified Ad" android:textAppearance="@style/TextAppearance.AppCompat.Headline" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <android.support.design.widget.TextInputLayout android:id="@+id/title_la" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/add_head_tv"> <android.support.design.widget.TextInputEditText android:id="@+id/title_a" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Title"/> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/category_la" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/title_la"> <android.support.design.widget.TextInputEditText android:id="@+id/category_a" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Category"/> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/desc_la" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/category_la"> <android.support.design.widget.TextInputEditText android:id="@+id/desc_a" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Description"/> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/name_la" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/desc_la"> <android.support.design.widget.TextInputEditText android:id="@+id/name_a" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Name"/> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/phone_la" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/name_la"> <android.support.design.widget.TextInputEditText android:id="@+id/phone_a" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Phone"/> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/city_la" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/phone_la"> <android.support.design.widget.TextInputEditText android:id="@+id/city_a" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="City"/> </android.support.design.widget.TextInputLayout> <Button android:id="@+id/post_add" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/Widget.AppCompat.Button.Colored" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/city_la" android:text="Post Add"/> </android.support.constraint.ConstraintLayout>

View Fragment

public class ViewClassifiedFragment extends Fragment { private static final String TAG = "ViewAdsFragment"; private DatabaseReference databaseReference; private RecyclerView adsRecyclerView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.ad_view_layout, container, false); databaseReference = FirebaseDatabase.getInstance().getReference(); Button button = (Button) view.findViewById(R.id.view_adds_b); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getClassifiedAds(); } }); adsRecyclerView = (RecyclerView) view.findViewById(R.id.ads_lst); LinearLayoutManager recyclerLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext()); adsRecyclerView.setLayoutManager(recyclerLayoutManager); DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(adsRecyclerView.getContext(), recyclerLayoutManager.getOrientation()); adsRecyclerView.addItemDecoration(dividerItemDecoration); return view; } @Override public void onAttach(Context context) { super.onAttach(context); } public void getClassifiedAds() { String category = ((TextView) getActivity() .findViewById(R.id.category_v)).getText().toString(); getClassifiedsFromDb(category); } private void getClassifiedsFromDb(final String category) { databaseReference.child("classified").orderByChild("category") .equalTo(category).addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { List<ClassifiedAd> adsList = new ArrayList<ClassifiedAd>(); for (DataSnapshot adSnapshot: dataSnapshot.getChildren()) { adsList.add(adSnapshot.getValue(ClassifiedAd.class)); } Log.d(TAG, "no of ads for search is "+adsList.size()); AdsRecyclerView recyclerViewAdapter = new AdsRecyclerView(adsList, getActivity()); adsRecyclerView.setAdapter(recyclerViewAdapter); } @Override public void onCancelled(DatabaseError databaseError) { Log.d(TAG, "Error trying to get classified ads for " +category+ " "+databaseError); Toast.makeText(getActivity(), "Error trying to get classified ads for " +category, Toast.LENGTH_SHORT).show(); } }); } }

View Fragment Layout

<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="zoftino.com.firebase.realtimedb.ClassifiedsActivity"> <TextView android:id="@+id/head_view_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:textAppearance="@style/TextAppearance.AppCompat.Headline" android:text="View Classifieds" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <android.support.design.widget.TextInputLayout android:id="@+id/category_lv" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" app:layout_constraintHorizontal_bias="0.22" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/head_view_tv"> <android.support.design.widget.TextInputEditText android:id="@+id/category_v" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Category" /> </android.support.design.widget.TextInputLayout> <Button android:id="@+id/view_adds_b" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" style="@style/Widget.AppCompat.Button.Colored" app:layout_constraintLeft_toRightOf="@+id/category_lv" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/head_view_tv" android:text="View Ads"/> <android.support.v7.widget.RecyclerView android:id="@+id/ads_lst" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/view_adds_b"/> </android.support.constraint.ConstraintLayout>

RecyclerView Adapter

public class AdsRecyclerView extends RecyclerView.Adapter<AdsRecyclerView.ViewHolder> { private List<ClassifiedAd> adsList; private Context context; public AdsRecyclerView(List<ClassifiedAd> list, Context ctx) { adsList = list; context = ctx; } @Override public int getItemCount() { return adsList.size(); } @Override public AdsRecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.ad_item_layout, parent, false); AdsRecyclerView.ViewHolder viewHolder = new AdsRecyclerView.ViewHolder(view); return viewHolder; } @Override public void onBindViewHolder(AdsRecyclerView.ViewHolder holder, int position) { final int itemPos = position; final ClassifiedAd classifiedAd = adsList.get(position); holder.title.setText(classifiedAd.getTitle()); holder.name.setText(classifiedAd.getName()); holder.phone.setText(classifiedAd.getPhone()); holder.edit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { editClassifiedAd(classifiedAd.getAdId()); } }); holder.delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { deleteClassifiedAd(classifiedAd.getAdId(), itemPos); } }); } public class ViewHolder extends RecyclerView.ViewHolder { public TextView title; public TextView name; public TextView phone; public Button edit; public Button delete; public ViewHolder(View view) { super(view); name = (TextView) view.findViewById(R.id.title_i); title = (TextView) view.findViewById(R.id.name_i); phone = (TextView) view.findViewById(R.id.phone_i); edit = view.findViewById(R.id.edit_ad_b); delete = view.findViewById(R.id.delete_ad_b); } } private void editClassifiedAd(String adId){ FragmentManager fm = ((ClassifiedsActivity)context).getSupportFragmentManager(); Bundle bundle=new Bundle(); bundle.putString("adId", adId); AddClassifiedFragment addFragment = new AddClassifiedFragment(); addFragment.setArguments(bundle); fm.beginTransaction().replace(R.id.adds_frame, addFragment).commit(); } private void deleteClassifiedAd(String adId, final int position){ FirebaseDatabase.getInstance().getReference() .child("classified").child(adId).removeValue() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { //remove item from list alos and refresh recyclerview adsList.remove(position); notifyItemRemoved(position); notifyItemRangeChanged(position, adsList.size()); Log.d("Delete Ad", "Classified has been deleted"); Toast.makeText(context, "Classified has been deleted", Toast.LENGTH_SHORT).show(); } else { Log.d("Delete Ad", "Classified couldn't be deleted"); Toast.makeText(context, "Classified could not be deleted", Toast.LENGTH_SHORT).show(); } } }); } }

RecyclerView Item Layout