Respecting Boundaries in Android: A Real Example with Firebase RecyclerView Adapter
In Android development, respecting boundaries between components isn’t just an academic design principle it’s essential for writing clean, scalable, and testable apps.
Recently, while working with Firebase and RecyclerView, I came across a common but powerful example of how boundaries can be blurred and how we can fix them to build better architecture. Let’s walk through a working example from a real app and discuss what works, what doesn’t, and how to do it better.
The Starting Point: Firebase + RecyclerView
Here’s a complete implementation of a Firebase RecyclerViewAdapter:
package np.com.ishwor.csit.adapter;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.firebase.ui.database.FirebaseRecyclerOptions;
import np.com.ishwor.csit.R;
import np.com.ishwor.csit.model.SemesterDataModel;
import np.com.ishwor.csit.ui.SemesterEightFragment;
import np.com.ishwor.csit.ui.SemesterFiveFragment;
import np.com.ishwor.csit.ui.SemesterFourFragment;
import np.com.ishwor.csit.ui.SemesterOneFragment;
import np.com.ishwor.csit.ui.SemesterSevenFragment;
import np.com.ishwor.csit.ui.SemesterSixFragment;
import np.com.ishwor.csit.ui.SemesterThreeFragment;
import np.com.ishwor.csit.ui.SemesterTwoFragment;
import np.com.ishwor.csit.viewholder.DataViewHolder;
public class RecyclerViewAdapter extends FirebaseRecyclerAdapter<SemesterDataModel, DataViewHolder> {
public interface OnItemClickListener {
void onItemClick(SemesterDataModel model, int position);
}
private final OnItemClickListener listener;
private final Context context;
public RecyclerViewAdapter(@NonNull FirebaseRecyclerOptions<SemesterDataModel> options, Context context, OnItemClickListener listener) {
super(options);
this.context = context;
this.listener = listener;
}
@Override
protected void onBindViewHolder(@NonNull DataViewHolder holder, int position, @NonNull SemesterDataModel model) {
holder.setName(model.getName());
holder.setImage(context, model.getImage());
holder.itemView.setBackgroundColor(Color.parseColor(model.getColor()));
// All fragments created here
final Fragment[] semesterFragments = new Fragment[]{
new SemesterOneFragment(),
new SemesterTwoFragment(),
new SemesterThreeFragment(),
new SemesterFourFragment(),
new SemesterFiveFragment(),
new SemesterSixFragment(),
new SemesterSevenFragment(),
new SemesterEightFragment()
};
holder.itemView.setOnClickListener(v -> {
int pos = holder.getAdapterPosition();
if (pos != RecyclerView.NO_POSITION) {
listener.onItemClick(model, pos);
}
});
}
@NonNull
@Override
public DataViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_items, parent, false);
return new DataViewHolder(view);
}
}
What’s Good About It
Let’s give credit where it’s due. This adapter does some great things:
FirebaseRecyclerAdapter is used properly to decouple Firebase query logic from the UI layer.
An interface (OnItemClickListener) handles item clicks, which is good separation from the adapter itself.
View binding is clean, done in the DataViewHolder.
This is a solid, production-ready adapter.
But Where Are the Boundaries Blurred?
Now, let’s look at the fragment creation inside onBindViewHolder():
final Fragment[] semesterFragments = new Fragment[]{
new SemesterOneFragment(),
new SemesterTwoFragment(),
…
};
This line is a red flag.
Creating and referencing specific Fragment instances inside your adapter tightly couples the adapter to the navigation layer. That’s not the adapter’s job. Its role is to bind views with data, not to decide what screen comes next.
This kind of logic should live in the host Activity or Fragment, where navigation decisions are typically made.
Respecting Boundaries: The Fix
The good news is: you’re already almost there.
The adapter exposes this:
listener.onItemClick(model, pos);
Now, in your Fragment or Activity, handle the logic like this:
adapter = new RecyclerViewAdapter(options, getContext(), (model, position) -> {
Fragment fragment = null;
switch (position) {
case 0: fragment = new SemesterOneFragment(); break;
case 1: fragment = new SemesterTwoFragment(); break;
case 2: fragment = new SemesterThreeFragment(); break;
case 3: fragment = new SemesterFourFragment(); break;
case 4: fragment = new SemesterFiveFragment(); break;
case 5: fragment = new SemesterSixFragment(); break;
case 6: fragment = new SemesterSevenFragment(); break;
case 7: fragment = new SemesterEightFragment(); break;
}
if (fragment != null) {
requireActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit();
}
});
This keeps your adapter clean, and gives your navigation logic a proper home in the UI controller (which is where it belongs).
Why Boundaries Matter
When responsibilities are clearly divided:
- Your code becomes more maintainable and testable.
- You can reuse components (e.g., the adapter in multiple fragments).
- Bugs are easier to isolate and fix.
- The mental load for you and your team decreases.
Think of boundaries as contracts between components. The adapter promises only to bind data to views not to manage fragment transactions.
Final Thoughts
Your original code is already clean and functional, and it demonstrates some solid architectural principles. With a small change—moving fragment logic out of the adapter—you’ve fully respected the boundaries and created a reusable, flexible system.
Keep your adapters dumb, and your UI controllers smart.
Boundaries are where good software architecture begins.
If you found this post helpful, let me know how you handle RecyclerView boundaries in your apps. Or feel free to share your own FirebaseRecyclerAdapter patterns!
#AndroidDev #Firebase #RecyclerView #CleanArchitecture #Java #AndroidStudio #SoftwareDesign
Happy coding 🙂
Leave a Reply