How to Access Many Nested Child Firebase Realtime database into RecyclerView? - java

Can anyone here help me?
how to display the "Episode" and "Pemeran" sections in the recyclerView on the second display in the following image.
I use the same method as "liveTV" but it doesn't work / appears anything, because of the many children in the Episode and Pemeran tables?
please help, thank you
Firebase Realtime-database picture]
Application Concept
dbDrakorAdapter.java - Models
public class dbDrakorAdapter {
private String LinkMovie;
private String List;
private String FotoPemain;
private String NamaPemain;
public dbDrakorAdapter (String linkMovie, String list, String fotoPemain, String namaPemain) {
LinkMovie = linkMovie;
List = list;
FotoPemain = fotoPemain;
NamaPemain = namaPemain;
}
public class Episode {
List<EpisodeDetails> episodeDetails;
}
public class EpisodeDetails {
// public Long chapterId;
public String LinkMovie;
public String List;
}
public class Pemeran {
List<PemeranDetails> pemeranDetails;
}
public class PemeranDetails {
// public Long chapterId;
public String LinkMovie;
public String List;
}
#PropertyName("LinkMovie")
public String getLinkMovie() { return LinkMovie; }
#PropertyName("List")
public String getList() { return List; }
#PropertyName("FotoPemain")
public String getFotoPemain() { return FotoPemain; }
#PropertyName("NamaPemain")
public String getNamaPemain() { return NamaPemain; }
#Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("List", List);
result.put("LinkMovie", LinkMovie);
result.put("FotoPemain", FotoPemain);
result.put("NamaPemain", NamaPemain);
return result;
}
}
DrakorActivity.Java
public class DrakorActivity extends AppCompatActivity {
private RecyclerView mEpisodeRV,mPemeranRV;
private FirebaseRecyclerAdapter<dbDrakorAdapter, DrakorActivity.ListEpisode> mListEpisodeAdapter;
private FirebaseRecyclerAdapter<dbDrakorAdapter, DrakorActivity.ListPemeran> mListPemeranAdapter;
FirebaseDatabase firebaseDatabase;
DatabaseReference databaseReference;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drakor);
DatabaseReference database = FirebaseDatabase.getInstance().getReference("SerialDrakor").child("Episode");
Query personsQuery = database.orderByKey();
mEpisodeRV = (RecyclerView) findViewById(R.id.cRecylerDrakorEpisode);
mEpisodeRV.setHasFixedSize(true);
mEpisodeRV.setLayoutManager(new LinearLayoutManager(this));
FirebaseRecyclerOptions personsOptions = new FirebaseRecyclerOptions.Builder<dbDrakorAdapter>().setQuery(personsQuery, dbDrakorAdapter.class).build();
mListEpisodeAdapter = new FirebaseRecyclerAdapter<dbDrakorAdapter, ListEpisode>(personsOptions) {
#Override
protected void onBindViewHolder(DrakorActivity.ListEpisode holder, int position, final dbDrakorAdapter model ) {
holder.setList(model.getList());
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(DrakorActivity.this,"Ini Hanya Iklan , Tidak Dapat Digunakan",Toast.LENGTH_LONG).show();
}
});
}
#Override
public DrakorActivity.ListEpisode onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_drakor_episode, parent, false);
return new DrakorActivity.ListEpisode(view);
}
};
LinearLayoutManager layoutManager = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);
mEpisodeRV.setLayoutManager(layoutManager);
mEpisodeRV.setAdapter(mListEpisodeAdapter);
}
#Override
public void onStart() {
super.onStart();
mListEpisodeAdapter.startListening();
// mListPemeranAdapter.startListening();
}
#Override
public void onStop() {
super.onStop();
mListEpisodeAdapter.stopListening();
// mListPemeranAdapter.stopListening();
}
//Episode
public static class ListEpisode extends RecyclerView.ViewHolder{
View mView;
public ListEpisode(View itemView){
super(itemView);
mView = itemView;
}
public void setList (String list){
TextView post_title = (TextView)mView.findViewById(R.id.TxtlistEpisode);
post_title.setText(list);
}
}
activity_drakor.xml
<LinearLayout
android:id="#+id/drakorLyEpisode"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_below="#id/drakorThumbnail"
android:background="#color/colorAccent"
android:orientation="horizontal">
<android.support.v7.widget.RecyclerView
android:id="#+id/cRecylerDrakorEpisode"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
item_drakor_episode.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="60dp"
android:layout_height="30dp"
android:orientation="horizontal"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardBackgroundColor="#090000"
app:cardCornerRadius="15dp">
<TextView
android:id="#+id/TxtlistEpisode"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#ffffff"
android:textSize="20dp"
android:text="1"
android:textAlignment="center"
android:textStyle="bold" />
</android.support.v7.widget.CardView>

On deep seeing your firebase structure it is difficult to query as you said.So you can change your firebase structure as below
Episode
|
|__Unique_Key
|
|__LinkMovie:"asasa.com
|__List:"1"
|__Epi:"1"
Pemeran
|
|__UniqueKey
|__fotoPermain:"...."
|__NamaPemain:"Ronny"
|__permeranId:"1"
Here,SubNode 1 in your Episode and pemeran Node in your firebase structure is replace as the Child Node of Unique Key.
You can generate Unique Key by push()

Your FirebaseRecyclerAdapters are using the same POJO but they are going to display different information.
For example:
FirebaseRecyclerAdapter<EpisodePojo, DrakorActivity.ListEpisode> listEpisodesAdapter
FirebaseRecyclerAdapter<PemeranPojo, DrakorActivity.ListPemeran> listPemeranAdapter
Your code is not showing any information probably because your DatabaseReference is trying to access "Episode as a child of SerialDrakor" but "SerialDrakor" is a list of objects, therefore, your code will not be able to parse a list of "SerialDrakor" child into "Episode".
You have to retrieve "SerialDrakor" as a list and use the child you need from this list to retrieve the "Episode" and "Pemeran" inside of it.
Here you can see some examples, maybe would be a good idea to use a custom parser.
https://github.com/firebase/FirebaseUI-Android/tree/master/database#using-the-firebaserecycleradapter
Update: What I would do is create a class parsing a "SerialDrakor" item.
class SerialDrakor {
List<Episode> episodeList;
List<Pemeran> pemeranList;
.....
}
Then use a query to retrieve "SerialDrakor"
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
Query serialDrakorQuery = database.child("SerialDrakor").orderByKey();
FirebaseRecyclerOptions personsOptions = new FirebaseRecyclerOptions.Builder<SerialDrakor>().setQuery(serialDrakorQuery, new SnapshotParser<SerialDrakor>() {
#Override
public SerialDrakor parseSnapshot(#NonNull DataSnapshot snapshot) {
// Here fetch the data you want and pass it to your adapters
}
I hope it helps.

Related

Error in layout output:: RecyclerView: No Adapter attached; Skipping Layout

Upon trying to load a "log viewer" I'm building, the original pre-set layout doesn't show as output. I do get the appropriate output from my Firebase database, but the layout is all messed up/way too spaced. What am I doing wrong?
This is my LogActivity Class
public class LogActivity extends AppCompatActivity {
List<Log> log;
RecyclerView recyclerView;
LogAdapter logAdapter;
DatabaseReference databaseReference;
DatabaseReference mbase; // Create object of the
// Firebase Realtime Database
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log);
recyclerView=findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
log=new ArrayList<>();
databaseReference = FirebaseDatabase.getInstance().getReference("Logs");
databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for(DataSnapshot ds: snapshot.getChildren())
{
Log data = new Log(ds.getValue(String.class));
log.add(data);
}
logAdapter = new LogAdapter(log);
recyclerView.setAdapter(logAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
My Adapter Class is as shown below:
public class LogAdapter extends RecyclerView.Adapter {
List<Log> logList;
public LogAdapter(List<Log> logList) {
this.logList = logList;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.log_layout, parent,false);
ViewHolderClass viewHolderClass = new ViewHolderClass(view);
return viewHolderClass;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
ViewHolderClass viewHolderClass=(ViewHolderClass)holder;
Log log=logList.get(position);
viewHolderClass.lockState.setText(log.getLockState());
}
#Override
public int getItemCount() {
return logList.size();
}
public class ViewHolderClass extends RecyclerView.ViewHolder{
TextView lockState;
public ViewHolderClass(#NonNull View itemView) {
super(itemView);
lockState=itemView.findViewById(R.id.log_string);
}
}
All of this interlocks with my " log" class which simply holds a string from my firebase DB
public class Log {
private String lockState;
public Log() {
}
public Log(String lockState) {
this.lockState = lockState;
}
public String getLockState() {
return lockState;
}
public void setLockState(String lockState) {
this.lockState = lockState;
}
The following is the XML for my activity_log
<RelativeLayout
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:id="#+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/cardBackground"
tools:context=".LogActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="4dp"
android:layout_marginTop="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
XML for my log_layout file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/log_layout"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/log_string"
android:text="20sp"
android:textColor="#android:color/black">
</TextView>
Lastly here are the simple strings I'm fetching and displaying successfully:
firebase-database
With my actual output here:
(scroll down and the next output is there)
app-output
You are getting the following warning, as it's not an Error nor an Exception:
Error in layout output:: RecyclerView: No Adapter attached; Skipping Layout
Because you are trying to read "Log" objects that don't exist in the "Logs" location in your database. If Log objects existed there, your database schema would have been looking like this:
Firebase-root
|
--- Logs
|
--- -MW6C...tJ_2
|
--- lockState: "14h01 - Connected - Locker is NOT empty"
Meaning that under the Logs node, you have a pushed key under which exists an object of type "Log". In your schema, you only have pushed keys that only hold some Strings, hence that warning. There are two solutions. The first is to change the schema as explained above, or to use an adapter class of type String, and not Log.

How to retrieve images From Firebase Database And display it in a RecylerView?

I want to retrieve images from the firebase database and show it in a recyclerview. The images are already uploaded in the database and the firebase storage. But can't seem to figure out how to retrieve the images. So far I have tried the below method but can only retrieve the Textviews.
Activity.java
public class AssetListActivity extends AppCompatActivity {
private FloatingActionButton mAddAssetBtn;
private Toolbar mToolBar;
private DatabaseReference mAssetDatabase;
private RecyclerView mAssetRecyclerView;
private DatabaseReference mAssetIndDatabase;
String barcode;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_asset_list);
//Finding The Toolbar with it's unique Id.
mToolBar = (Toolbar) findViewById(R.id.main_page_toolbar);
mToolBar.setTitle("All Assets");
//Setting Up the ToolBar in The ActionBar.
setSupportActionBar(mToolBar);
barcode = getIntent().getStringExtra("barcode");
mAssetDatabase = FirebaseDatabase.getInstance().getReference().child("Assets");
mAssetDatabase.keepSynced(true);
mAssetRecyclerView = (RecyclerView) findViewById(R.id.assetRecyclerView);
mAssetRecyclerView.setHasFixedSize(true);
mAssetRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mAddAssetBtn = (FloatingActionButton) findViewById(R.id.addAssetBtn);
mAddAssetBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(AssetListActivity.this , AddAssetActivity.class);
startActivity(intent);
}
});
}
#Override
protected void onStart() {
super.onStart();
Query query = mAssetDatabase.orderByChild("asset_name").limitToLast(50);
//Setting the up the FirebaseRecycerOption and passing the Model of the Data and the query of the Database.
FirebaseRecyclerOptions<AssetModel> options = new FirebaseRecyclerOptions.Builder<AssetModel>()
.setQuery(query, AssetModel.class).build();
FirebaseRecyclerAdapter<AssetModel , AssetViewHolder> recyclerAdapter = new FirebaseRecyclerAdapter<AssetModel , AssetViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull AssetViewHolder assetViewHolder, int i, #NonNull AssetModel assetModel) {
assetViewHolder.setAssetName(assetModel.getAsset_name());
assetViewHolder.setAssetDescription(assetModel.getAsset_description());
assetViewHolder.setAssetLocation(assetModel.getAsset_location());
assetViewHolder.setAssetImage(assetModel.getAsset_image());
}
#NonNull
#Override
public AssetViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//Setting up the LayoutInflater and passing on the SingleUserLayout.
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.single_asset_layout, parent, false);
//Returning the UserViewHolder
return new AssetViewHolder(view);
}
};
mAssetRecyclerView.setAdapter(recyclerAdapter);
recyclerAdapter.startListening();
}
public static class AssetViewHolder extends RecyclerView.ViewHolder {
View mView;
public AssetViewHolder(#NonNull View itemView) {
super(itemView);
mView = itemView;
}
//Creating a new Method to set the Name in the RecyclerView.
public void setAssetName(String assetName) {
//Finding the TextView if the name with it's unique Id.
TextView mSingleAssetName = mView.findViewById(R.id.assetTitle);
mSingleAssetName.setText(assetName);
}
//Creating a new Method to set the Status in the RecyclerView.
public void setAssetDescription(String assetDescription) {
//Finding the TextView of the status with it's unique Id.
TextView mSingleAssetDescription = mView.findViewById(R.id.assetDescription);
mSingleAssetDescription.setText(assetDescription);
}
public void setAssetLocation(String assetLocation) {
//Finding the TextView of the status with it's unique Id.
TextView mSingleAssetLocation = mView.findViewById(R.id.assetLocation);
mSingleAssetLocation.setText(assetLocation);
}
//Creating a new Method to set the asset_image in the RecyclerView.
public void setAssetImage(String asset_image) {
ImageView mAssetImgView = mView.findViewById(R.id.assetImg);
Log.d("URL000025123" , asset_image);
Picasso.get().load(asset_image).placeholder(R.drawable.default_avatar_img).into(mAssetImgView);
}
}
}
Model.java
public class AssetModel {
private String asset_name;
private String asset_description;
private String asset_location;
private String asset_image;
public AssetModel() {
}
public AssetModel(String asset_name, String asset_description, String asset_location, String asset_image) {
this.asset_name = asset_name;
this.asset_description = asset_description;
this.asset_location = asset_location;
this.asset_image = asset_image;
}
public String getAsset_name() {
return asset_name;
}
public void setAsset_name(String asset_name) {
this.asset_name = asset_name;
}
public String getAsset_description() {
return asset_description;
}
public void setAsset_description(String asset_description) {
this.asset_description = asset_description;
}
public String getAsset_location() {
return asset_location;
}
public void setAsset_location(String asset_location) {
this.asset_location = asset_location;
}
public String getAsset_image() {
return asset_image;
}
public void setAsset_image(String asset_image) {
this.asset_image = asset_image;
}
}
Style.XML
<RelativeLayout
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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="180dp"
android:background="#EEEEEE">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="180dp"
android:background="#FFF"
android:layout_marginTop="8dp">
<ImageView
android:id="#+id/assetImg"
android:layout_width="58dp"
android:layout_height="58dp"
app:srcCompat="#drawable/default_avatar_img"
android:layout_marginTop="15dp"
android:layout_marginStart="10dp"/>
<TextView
android:id="#+id/assetTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginTop="15dp"
android:layout_toEndOf="#+id/assetImg"
android:fontFamily="#font/raleway_medium"
android:text="This is the Title"
android:textColor="#212423"
android:textSize="20sp" />
<TextView
android:id="#+id/assetDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/assetTitle"
android:layout_marginStart="30dp"
android:layout_marginTop="10dp"
android:layout_toEndOf="#id/assetImg"
android:fontFamily="#font/raleway"
android:maxLines="2"
android:text="This is Asset Description"
android:textSize="16sp"
android:layout_marginBottom="10dp"/>
<TextView
android:id="#+id/assetLocation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/assetDescription"
android:layout_marginStart="30dp"
android:layout_toEndOf="#id/assetImg"
android:fontFamily="#font/raleway"
android:maxLines="3"
android:text="Location Of Asset"
android:textSize="17sp"
android:layout_marginBottom="5dp"/>
</RelativeLayout>
I can retrieve other data such as Name And Description but can't seem to figure out how to retrieve the images and how to display them in a recyclerview.
Firebase JSON data.
I figured it out. If you write your read and write rules in the firebase storage in separate lines, this solves the error.
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow write: if request.auth != null;
allow read: if true;
}
}
}

How to get data from cloud firestore and display it with recycler view

I have a cloud firestore database with a collection named Bus and three documents inside it as it is shown in the image
database picture
I have followed what is written in this link
How to display data from Firestore in a RecyclerView with Android?
three recycler views are being created and displayed but with empty data
also when I add a fourth document to Bus four recycler views are being created and displayed but with empty data
can you tell me how to fix my code?
model:
public class Bus {
public Bus(String driverName, int busNo, String contactNo) {
this.driverName = driverName;
this.busNo = busNo;
this.contactNo = contactNo;
}
public Bus(){ }
public String getDriverName() {
return driverName;
}
public void setDriverName(String driverName) {
this.driverName = driverName;
}
public int getBusNo() {
return busNo;
}
public void setBusNo(int busNo) {
this.busNo = busNo;
}
public String getContactNo() {
return contactNo;
}
public void setContactNo(String contactNo) {
this.contactNo = contactNo;
}
String driverName, contactNo;
int busNo ;
}
activity code :
public class ViewBusDetailes extends AppCompatActivity {
LinearLayoutManager linearLayoutManager;
FirestoreRecyclerAdapter<Bus, BusViewHolder> adapter;
class BusViewHolder extends RecyclerView.ViewHolder {
private View view;
BusViewHolder(View itemView) {
super(itemView);
view = itemView;
}
void setDetiles(String contactNoText , String driverNameText, int busNoText) {
TextView driverName;
TextView busNo;
TextView contactNo;
driverName = itemView.findViewById(R.id.driverNameDriverListView);
contactNo = itemView.findViewById(R.id.driverContactDriverListView);
busNo = itemView.findViewById(R.id.busNumber);
driverName.setText(driverNameText);
busNo.setText(String.valueOf(busNoText));
contactNo.setText(contactNoText);
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_bus_details__layout);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
Query query = rootRef.collection("Bus");
FirestoreRecyclerOptions<Bus> options = new FirestoreRecyclerOptions.Builder<Bus>()
.setQuery(query, Bus.class)
.build();
adapter = new FirestoreRecyclerAdapter<Bus, BusViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull BusViewHolder holder, int position, #NonNull Bus model) {
holder.setDetiles(model.getContactNo() , model.getDriverName() ,model.getBusNo());
}
#NonNull
#Override
public BusViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.bus_list_view, parent, false);
return new BusViewHolder(view);
}
};
recyclerView.setAdapter(adapter);
}
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
if (adapter != null) {
adapter.stopListening();
}
}
}
bus_list_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="360dp"
android:layout_height="72dp"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:padding="16dp">
<TextView
android:id="#+id/busNumber"
android:layout_width="40dp"
android:layout_height="40dp"
android:textSize="20sp"
android:gravity="center"
android:fontFamily="sans-serif"
android:textStyle="normal"
android:textColor="#ffffff"
android:background="#drawable/circle"
/>
<LinearLayout
android:layout_width="287dp"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/driverNameDriverListView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:textSize="17sp"
android:fontFamily="sans-serif"
android:textStyle="normal"
android:textColor="#de000000"
android:lineSpacingExtra="8sp"
android:text="Anwar"
/>
<TextView
android:id="#+id/driverContactDriverListView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_marginLeft="17dp"
android:fontFamily="sans-serif"
android:textStyle="normal"
android:textColor="#de000000"
android:lineSpacingExtra="6sp"
android:text="Dude can you solve this problem plea..."
/>
</LinearLayout>
</LinearLayout>
activity_view_bus_detiels.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".activity.ViewBusDetailes"
android:id="#+id/container">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Do it like this
public class Bus {
private String driverName;
private int busNo;
private String contactNo;
public String getDriverName() {
return driverName;
}
public int getBusNo() {
return busNo;
}
public String getContactNo() {
return contactNo;
}
}
activity code :
public class ViewBusDetailes extends AppCompatActivity {
LinearLayoutManager linearLayoutManager;
FirestoreRecyclerAdapter adapter;
class BusViewHolder extends RecyclerView.ViewHolder {
TextView driverName;
TextView busNo;
TextView contactNo;
BusViewHolder(View itemView) {
super(itemView);
driverName = itemView.findViewById(R.id.driverNameDriverListView);
contactNo = itemView.findViewById(R.id.driverContactDriverListView);
busNo = itemView.findViewById(R.id.busNumber);
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_bus_details__layout);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
Query query = rootRef.collection("Bus");
FirestoreRecyclerOptions<Bus> options = new FirestoreRecyclerOptions.Builder<Bus>()
.setQuery(query, Bus.class)
.build();
adapter = new FirestoreRecyclerAdapter<Bus, BusViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull BusViewHolder holder, int position, #NonNull Bus model) {
holder.driverName.setText(model.getDriverName());
holder.busNo.setText(String.valueOf(model.getBusNo()));
holder.contactNo.setText(model.getContactNo());
}
#NonNull
#Override
public BusViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(ViewBusDetailes.this).inflate(R.layout.bus_list_view, parent, false);
return new BusViewHolder(view);
}
};
recyclerView.setAdapter(adapter);
}
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
if (adapter != null) {
adapter.stopListening();
}
}
}
Also, add this dependency if you haven't.
implementation 'com.firebaseui:firebase-ui-firestore:4.3.2'
Also, edit your Firebase Firestore rules from Firestore settings in the firebase console.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Check if it works.

Firestore recycler adapter not fetching document names

I'm trying fetch all documents using FirestoreRecyclerAdapter here if there are 7 documents the RecyclerView items successfully populates with 7 items but here problem is the items which are having a text view are not getting populated with document names. Please take a look at my source code:
FriendsResponse Class:
#IgnoreExtraProperties
public class FriendsResponse {
FirebaseFirestore db;
public String getTable1() {
return Table1;
}
public void setTable1(String table1) {
Table1 = table1;
}
private String Table1;
public FriendsResponse() {
}
public FriendsResponse(String Table1) {
this.Table1 = Table1;
}
}
TableList Fragment where recyclerview is initialized:
public class TableListFragment extends Fragment{
private FirebaseFirestore db;
private FirestoreRecyclerAdapter adapter;
String documentnm;
RecyclerView recyclerView;
FloatingActionButton addt;
private StaggeredGridLayoutManager _sGridLayoutManager;
public static TableListFragment newInstance() {
TableListFragment fragment = new TableListFragment();
return fragment;
}
public TableListFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_tablelist, container, false);
recyclerView = view.findViewById(R.id.rectab);
addt=view.findViewById(R.id.addtab);
init();
getFriendList();
addt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
return view;
}
private void init(){
_sGridLayoutManager = new StaggeredGridLayoutManager(3,
StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(_sGridLayoutManager);
db = FirebaseFirestore.getInstance();
}
private void getFriendList(){
Query query = db.collection("Order");
FirestoreRecyclerOptions<FriendsResponse> response = new FirestoreRecyclerOptions.Builder<FriendsResponse>()
.setQuery(query, FriendsResponse.class)
.build();
adapter = new FirestoreRecyclerAdapter<FriendsResponse, FriendsHolder>(response) {
#Override
public void onBindViewHolder(FriendsHolder holder, int position, FriendsResponse model) {
holder.exname.setText(model.getTable1());
holder.itemView.setOnClickListener(v -> {
Snackbar.make(recyclerView, model.getTable1(), Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
});
}
#Override
public FriendsHolder onCreateViewHolder(ViewGroup group, int i) {
View view = LayoutInflater.from(group.getContext())
.inflate(R.layout.list_item, group, false);
return new FriendsHolder(view);
}
#Override
public void onError(FirebaseFirestoreException e) {
Log.e("error", e.getMessage());
}
};
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
}
public class FriendsHolder extends RecyclerView.ViewHolder {
TextView exname;
public FriendsHolder(View itemView) {
super(itemView);
exname= itemView.findViewById(R.id.topicname);
}
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void onDetach() {
super.onDetach();
}
}
This is the code of list_item:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView android:id="#+id/cardvw"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="6dp"
card_view:cardElevation="3dp"
card_view:cardUseCompatPadding="true"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto">
<LinearLayout android:orientation="vertical" android:padding="5dp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="5dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/topiclogo"
android:layout_width="match_parent"
android:layout_gravity="center"
android:src="#drawable/table"
android:layout_height="wrap_content"
/>
<TextView android:textSize="15sp"
android:textStyle="bold"
android:textAlignment="center"
android:textColor="#ffffa200"
android:id="#+id/topicname"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v7.widget.CardView>
As I understand, you want to set the id of the document to that TextView. So because those names are actually documents ids, you should use the following lines of code inside onBindViewHolder() method:
String id = getSnapshots().getSnapshot(position).getId();
holder.exname.setText(id);
The POJO class that you are using is useful when getting the properties of the documents, not to get the document ids.

What is the best practice for updating a RecyclerView within View.OnClick?

Not certain the best way to tackle this. I have a RecyclerView that represents a list of records from a database (I'm using SugarOrm; but, that's inconsequential to the question).
I'd like to represent data changes and allow the user to do CRUD functionality via onClick and onLongClick events. For example, if a user long-presses on a view in the RecyclerView, I'd like them to have the option to delete the record. The problem is that an update is easy to reflect in the view using only the ViewHolder; but, deleting a record is not so easy. The ViewHolder, as a static inner class, doesn't have access to the RecyclerView itself to to modify the adapter data or notify that the data changed.
One option is that I could make the inner ViewHolder class not static; but, should I be concerned about potential memory leaks? It feels like that would be the simplest solution; but, is there completely different pattern that I should be using (such as having another class be the onClickListener)?
I'd like to keep my code readable and as standard practice as I can; but, not if it will violate best practices or become inefficient.
See below for clarity.
SugarOrm Model Class to Display In ViewHolder:
public class SomeModel extends SugarRecord{
#Column(name="Name")
public String name;
#Column(name="AddedDate")
public Date addedDate = new Date();
}
RecyclerViewAdapter and ViewHolder:
public class SomeModelRecyclerViewAdapter
extends RecyclerView.Adapter<SomeModelRecyclerViewAdapter.ViewHolder>{
private List<SomeModel> data;
public SomeModelRecyclerViewAdapter(List<SomeModel> data) {
this.data = data;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.model_item, parent, false);
ViewHolder holder = new ViewHolder(view);
view.setOnClickListener(holder);
view.setOnLongClickListener(holder);
return holder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.someModel = data.get(position);
holder.bindData();
}
#Override
public int getItemCount() {
return data.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnLongClickListener {
private static final SimpleDateFormat dateFormat =
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
SomeModel someModel;
TextView modelNameLabel;
TextView modelDateLabel;
public SomeModel getSomeModel() {
return someModel;
}
public void setSomeModel(SomeModel someModel) {
this.someModel = someModel;
}
public ViewHolder(View itemView) {
super(itemView);
}
public void bindData() {
modelNameLabel = (TextView) itemView.findViewById(R.id.modelNameLabel);
modelDateLabel = (TextView) itemView.findViewById(R.id.modelDateLabel);
modelNameLabel.setText(someModel.name);
modelDateLabel.setText(dateFormat.format(someModel.addedDate));
}
#Override
public void onClick(View v) {
someModel.addedDate = new Date();
someModel.save();
bindData();
}
#Override
public boolean onLongClick(View v) {
someModel.delete();
return true;
}
}
}
Activity:
public class MainActivity extends AppCompatActivity {
EditText modelName;
Button addModelButton;
RecyclerView modelList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
modelName = (EditText) findViewById(R.id.modelName);
addModelButton = (Button) findViewById(R.id.addModelButton);
modelList = (RecyclerView) findViewById(R.id.modelList);
addModelButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SomeModel newRecord = new SomeModel();
newRecord.name = modelName.getText().toString();
newRecord.save();
setupRecyclerView();
}
});
setupRecyclerView();
}
private void setupRecyclerView() {
List<SomeModel> allModels = SomeModel.listAll(SomeModel.class);
SomeModelRecyclerViewAdapter adapter = new SomeModelRecyclerViewAdapter(allModels);
modelList.setHasFixedSize(true);
modelList.setLayoutManager(new LinearLayoutManager(this));
modelList.setAdapter(adapter);
}
}
Activity layout (activity_main.xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.aaronmbond.recyclerviewdilemaexample.MainActivity">
<EditText
android:id="#+id/modelName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
/>
<Button
android:id="#+id/addModelButton"
android:layout_alignParentStart="true"
android:layout_below="#id/modelName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/addModelButtonText"
/>
<android.support.v7.widget.RecyclerView
android:id="#+id/modelList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/addModelButton"
android:layout_alignParentStart="true"
/>
</RelativeLayout>
RecyclerView Item Layout (model_item.xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/modelNameLabel"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="#+id/modelDateLabel"
android:layout_alignParentStart="true"
android:layout_below="#id/modelNameLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</RelativeLayout>
I ran into a similar requirement few days back. You are right about the part - The ViewHolder, as a static inner class, doesn't have access to the RecyclerView itself to to modify the adapter data or notify that the data changed.
So the way to handle this is to define an interface which encapsulates all operations within your viewholder which it need to trigger something on the RecyclerView. Sample interface definition from my code -
/**
* Parent fragment or activity to implement this interface to listen to item deletes.
* Item deletes effect the state of the parent
*/
public interface OnItemModifiedListener {
void itemDeleted(Cart.CartItem item);
void itemQuantityChanged(Cart.CartItem item, int newQuantity);
void itemRemovedAll();
}
The parent fragment or Activity implements this interface and passes it on to the Adapter as part of it's constructor. Sample constructor from my code again -
public SimpleItemRecyclerViewAdapter(Context context, List<Cart.CartItem> items, OnItemModifiedListener l) {
//this variable is declared as a adapter state variable
mItemModifiedListener = l;
}
Now when a certain operation happens within your viewholder (specifically clicks) then invoke the appropriate method on this interface. Sample again from my code where i invoke this interface when a row is deleted -
holder.mDeleteView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//show an alert to user to confirm before remving the item from cart
AlertDialog alertDialog = new AlertDialog.Builder(getActivity()).create();
//alertDialog.setTitle("Alert");
alertDialog.setMessage(getString(R.string.alert_remove_item_from_cart_text));
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(android.R.string.ok),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mValues.remove(holder.mItem);
if(null != mItemModifiedListener)mItemModifiedListener.itemDeleted(holder.mItem);
notifyItemRemoved(position);
//notifyDataSetChanged();
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, getString(android.R.string.no),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
});
the below link is a good read too - https://antonioleiva.com/recyclerview-listener/
Hope this helps...

Categories