Android: Passing variables that allows recyclerview to be populated by specific strings - java

I'm trying to create a code saying "Where the username that is logged in matches the username of a created recipe, only show these database entries in the recyclerview on my MyRecipes.java activity". I'm having trouble working out where to put this potential statement. Looking at my code, where would you put that statement, if or otherwise?
The userLoggedIn and loggedUser is the variable for the currently logged in user.
The thisUser is what I've set as the users pulled from the database when the recyclerview is populating in the recyclerview.java class.
Any help would be greatly appreciated!
RecyclerView.java class
private static String thisUser;
String userLoggedIn = HomeActivity.getUserLogged();
private Context mContext;
private RecipesAdapter mRecipeAdapter;
public void setConfig (RecyclerView recyclerView, Context context, List<Recipes> recipes, List<String> keys){
mContext = context;
mRecipeAdapter = new RecipesAdapter(recipes, keys);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setAdapter(mRecipeAdapter);
}
class RecipeItemView extends RecyclerView.ViewHolder{
private TextView mTitle;
private TextView mIngredients;
private TextView mMethod;
private TextView mUser;
private String key;
public RecipeItemView(ViewGroup parent){
super(LayoutInflater.from(mContext).inflate(R.layout.recipe_list_item, parent,false));
mTitle = (TextView) itemView.findViewById(R.id.tvTitle);
mMethod = (TextView) itemView.findViewById(R.id.tvMethod);
mIngredients = (TextView) itemView.findViewById(R.id.tvIngredients);
mUser = (TextView) itemView.findViewById(R.id.tvUser);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, RecipeDetails.class);
intent.putExtra("key", key);
intent.putExtra("title", mTitle.getText().toString());
intent.putExtra("ingredients", mIngredients.getText().toString());
intent.putExtra("method", mMethod.getText().toString());
mContext.startActivity(intent);
}
});
}
public void bind(Recipes recipes, String key) {
mTitle.setText(recipes.getTitle());
mIngredients.setText(recipes.getIngredients());
mMethod.setText(recipes.getMethod());
mUser.setText(recipes.getCreatedUser());
thisUser = mUser.getText().toString().trim();
this.key = key;
}
}
public static String getUserLoggedIn(){
return thisUser;
}
class RecipesAdapter extends RecyclerView.Adapter<RecipeItemView> {
private List<Recipes> mRecipeList;
private List<String> mKeys;
public RecipesAdapter(List<Recipes> mRecipeList, List<String> mKeys) {
this.mRecipeList = mRecipeList;
this.mKeys = mKeys;
}
#NonNull
#Override
public RecipeItemView onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new RecipeItemView(parent);
}
#Override
public void onBindViewHolder(#NonNull RecipeItemView holder, int position) {
holder.bind(mRecipeList.get(position), mKeys.get(position));
}
#Override
public int getItemCount() {
return mRecipeList.size();
}
}
}
MyRecipes.java (Where the recycler view populates and shows all the recipes)
String loggedUser = HomeActivity.getUserLogged();
String thisUser = RecyclerViewConfig.getUserLoggedIn();
Button addRecipes;
private RecyclerView mRecyclerView;
private String passedUsername;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_recipes);
passedUsername = getIntent().getStringExtra("loggedUsername1");
mRecyclerView = (RecyclerView) findViewById(R.id.rvRecipes);
new FirebaseDatabaseHelper().readRecipes(new FirebaseDatabaseHelper.DataStatus() {
#Override
public void DataIsLoaded(List<Recipes> recipes, List<String> keys) {
new RecyclerViewConfig().setConfig(mRecyclerView, MyRecipesActivity.this, recipes, keys);
}
#Override
public void DataIsInserted() {
}
#Override
public void DataIsUpdated() {
}
#Override
public void DataIsDeleted() {
}
});
addRecipes = findViewById(R.id.btnAddNewRecipe);
addRecipes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent addrecipe = new Intent(MyRecipesActivity.this, AddRecipes.class);
addrecipe.putExtra("loggedUsername2", passedUsername);
startActivity(addrecipe);
}
});
}
}

If i understand correctly, you need to show the recipes to the user only if he/she is the one who created it? Assuming that, below change in the code will do the trick.
Change your bind() method as follows.
public void bind(Recipes recipes, String key) {
thisUser = mUser.getText().toString().trim();
if(thisUser.equals(recipes.getCreatedUser)) {
mTitle.setText(recipes.getTitle());
mIngredients.setText(recipes.getIngredients());
mMethod.setText(recipes.getMethod());
mUser.setText(recipes.getCreatedUser());
this.key = key;
}
}
Though that is a naive approach, a better approach would be to filter the recipes list with created user when you load data from Firebase with readRecipes() method itself. To do that a query can be used as below(the exact query below might not work for you depending on your DB structure. Change it as needed)
Query query = reference.child("Recipes").orderByChild("userCreated").equalTo(thisUser);

Related

RecyclerView crashes when I update data to Firestore

I'm showing data from a Firebase Firestore collection, the app worked fine while but when I update data to the collection from other device (I got an Arduino with sensors connected to a PC that executes a Python script to transform the serial data to JSON and then I update that data on the Firestore collection, all the back end of these functionality works perfectly. My problem it's the Java on Android.
I already search for solutions on this forum and It seems like something doesn't work with the Adapter, the RecyclerView and the "notifyDataSetChanged();" None of the current solutions worked for me or maybe I just don't know how to implement them on my project.
This is my model
public class Monitor {
String alias, placa, temp, acid;
public Monitor(){}
public Monitor(String alias, String placa, String temp, String acid) {
this.alias = alias;
this.placa = placa;
this.temp = temp;
this.acid = acid;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public String getPlaca() {
return placa;
}
public void setPlaca(String placa) {
this.placa = placa;
}
public String getTemp() {
return temp;
}
public void setTemp(String temp) {
this.temp = temp;
}
public String getAcid() {
return acid;
}
public void setAcid(String acid) {
this.acid = acid;
}
}
The adapter
public class MonitorAdapter extends FirestoreRecyclerAdapter<Monitor, MonitorAdapter.ViewHolder> {
private FirebaseFirestore mFirestore = FirebaseFirestore.getInstance();
Activity activity;
/**
* Create a new RecyclerView adapter that listens to a Firestore Query. See {#link
* FirestoreRecyclerOptions} for configuration options.
*
* #param options
*/
public MonitorAdapter(#NonNull FirestoreRecyclerOptions<Monitor> options, Activity activity) {
super(options);
this.activity = activity;
}
#Override
protected void onBindViewHolder(#NonNull ViewHolder holder, int position, #NonNull Monitor model) {
DocumentSnapshot documentSnapshot = getSnapshots().getSnapshot(holder.getAbsoluteAdapterPosition());
final String id = documentSnapshot.getId();
holder.alias.setText(model.getAlias());
holder.temp.setText(model.getTemp());
holder.acid.setText(model.getAcid());
holder.btn_edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(activity, VincularPlaca.class);
i.putExtra("id_placa",id);
activity.startActivity(i);
}
});
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_monitor_single,parent,false);
return new ViewHolder(view);
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView alias, temp, acid;
Button btn_edit;
public ViewHolder(#NonNull View itemView) {
super(itemView);
alias = itemView.findViewById(R.id.alias);
temp = itemView.findViewById(R.id.temp);
acid = itemView.findViewById(R.id.acid);
btn_edit = itemView.findViewById(R.id.btn_edit);
}
}
}
And my MainActivity
public class MainActivity extends AppCompatActivity {
Button btn_add, btn_exit;
RecyclerView mRecycler;
MonitorAdapter mAdapter;
FirebaseFirestore mFirestore;
FirebaseAuth mAuth;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFirestore = FirebaseFirestore.getInstance();
mRecycler = findViewById(R.id.recyclerViewSingle);
mRecycler.setLayoutManager(new LinearLayoutManager(this));
Query query = mFirestore.collection("dispositivos");
FirestoreRecyclerOptions<Monitor> firestoreRecyclerOptions =
new FirestoreRecyclerOptions.Builder<Monitor>().setQuery(query,Monitor.class).build();
mAdapter = new MonitorAdapter(firestoreRecyclerOptions, this);
mAdapter.notifyDataSetChanged();
mRecycler.setAdapter(mAdapter);
btn_add = findViewById(R.id.btn_add);
btn_exit = findViewById(R.id.btn_close);
btn_add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this,VincularPlaca.class));
}
});
btn_exit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this,LoginActivity.class));
mAuth.signOut();
}
});
}
#Override
protected void onStart() {
super.onStart();
mAdapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
mAdapter.stopListening();
}
}
class ExampleViewModel : ViewModel() {
var mFirestore : FirebaseFirestore? = null
private val _list = MutableLiveData<FirestoreRecyclerOptions<Monitor>>()
val list: LiveData<FirestoreRecyclerOptions<Monitor>> = _list
init{
mFirestore = FirebaseFirestore.getInstance()
list.value= FirestoreRecyclerOptions.Builder<Monitor>().setQuery(mFirestore!!.collection("dispositivos"),Monitor::class.java).build()
}
}
The problem has solved fixing the AndroidManifest Permissions and outside the code on the Firebase Firestore console, the attribute was supose to be an string but it recieves an int.

Populate details activity with Firebase Real Time Database after click on RecyclerView

i want to click in my recyclerview and open a new activity to show the datails. Ultil now i
have accomplished to open the activity and show the values "interno" and "siniiga" with the next intent. how can i get "madre and padre" values from firebase? applying the method to add father and mother, then I will use it for the rest of the values ​​that the xml shows. excuse my horrible code. if someone know a different method, let me know
attached code and images.
Main Activity
RecyclerView rv;
List<cow> vacas;
adapter adapter;
ImageButton mbuttoninf;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rv = (RecyclerView) findViewById(R.id.recyclerViewGirdView);
rv.setLayoutManager(new LinearLayoutManager(this));
vacas = new ArrayList<>();
FirebaseDatabase database = FirebaseDatabase.getInstance();
adapter = new adapter(vacas);
rv.setAdapter(adapter);
database.getReference("Vacas").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
vacas.removeAll(vacas);
for (DataSnapshot snapshot1 :
snapshot.getChildren()) {
cow vaca = snapshot1.getValue(cow.class);
vacas.add(vaca);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
cow
String interno;
String siniiga;
String ulr;
String madre;
String padre;
public cow() {
}
public cow(String interno, String siniiga, String ulr, String madre, String padre) {
this.interno = interno;
this.siniiga = siniiga;
this.ulr = ulr;
this.madre = madre;
this.padre = padre;
}
public String getInterno() {
return interno;
}
public void setInterno(String interno) {
this.interno = interno;
}
public String getSiniiga() {
return siniiga;
}
public void setSiniiga(String siniiga) {
this.siniiga = siniiga;
}
public String getUlr() {
return ulr;
}
public void setUlr(String ulr) {
this.ulr = ulr;
}
public String getMadre() {
return madre;
}
public void setMadre(String madre) {
this.madre = madre;
}
public String getPadre() {
return padre;
}
public void setPadre(String padre) {
this.padre = padre;
}
}
Adapter
List<cow> vacas;
Context context;
public adapter(List<cow> vacas) {
this.vacas = vacas;
}
#NonNull
#Override
public cowviewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_vaca,parent,false);
cowviewHolder holder = new cowviewHolder(v);
return holder;
}
#Override
public void onBindViewHolder(#NonNull final cowviewHolder holder, final int position) {
final cow vacaslist = vacas.get(position);
holder.textViewinterno.setText(String.valueOf(vacaslist.interno));
holder.textViewsiniiga.setText(String.valueOf(vacaslist.siniiga));
Glide.with(holder.imageviewrec.getContext()).load(vacaslist.getUlr()).into(holder.imageviewrec);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(v.getContext(),detailactivity.class);
intent.putExtra("keyint", vacaslist.getInterno());
intent.putExtra("keysin", vacaslist.getSiniiga());
v.getContext().startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return vacas.size();
}
public static class cowviewHolder extends RecyclerView.ViewHolder {
TextView textViewinterno, textViewsiniiga, tvmadre, tvpadre;
ImageView imageviewrec;
public cowviewHolder(#NonNull View itemView) {
super(itemView);
textViewinterno = itemView.findViewById(R.id.interno);
textViewsiniiga = itemView.findViewById(R.id.siniiga);
imageviewrec = itemView.findViewById(R.id.imgrec);
tvmadre = itemView.findViewById(R.id.tvmadre);
tvpadre = itemView.findViewById(R.id.tvpadre);
}
}
detailsactivity
TextView textView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.informationfire);
TextView tvinterno = (TextView) findViewById(R.id.tvinterno);
TextView tvsiniiga = (TextView) findViewById(R.id.tvsiniiga);
String vinterno = "";
String vsiniiga = "";
Bundle extras = getIntent().getExtras();
if (extras !=null);
vinterno = extras.getString("keyint");
vsiniiga = extras.getString("keysin");
tvinterno.setText(vinterno);
tvsiniiga.setText(vsiniiga);
}
}
firebase
enter image description here
and the xml for details
enter image description here
when you are getting data from firebase you saving that data in a Object and then add that object to list, so your list contains objects , so you can pass through the intents same way as you are doing others.
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(v.getContext(),detailactivity.class);
intent.putExtra("keyint", vacaslist.getInterno());
intent.putExtra("keysin", vacaslist.getSiniiga());
intent.putExtra("madre", vacaslist.getMadre());
intent.putExtra("padre", vacaslist.getPadre());
v.getContext().startActivity(intent);
}
});

Androidx RecycleView Not showing items with parse server

This is my adapter for recycle view
CategoryAdapter Class
public class CategoryRAdapter extends RecyclerView.Adapter<CategoryRAdapter.MyViewHolder> {
private Context mcontext;
private List<Food> mData;
RequestOptions option;
public CategoryRAdapter(Context mcontext, List<Food> mData) {
this.mcontext = mcontext;
this.mData = mData;
option = new RequestOptions().centerCrop().placeholder(R.drawable.loading_shape).error(R.drawable.loading_shape);
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.food_row, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Food current = mData.get(position);
holder.tv_Name.setText(current.getName());
holder.tv_Rating.setText(current.getRating());
holder.tv_Descip.setText(current.getDescrip());
holder.tv_Category.setText(current.getCateg());
Glide.with(mcontext).load(mData.get(position).getImages()).apply(option).into(holder.img_Thumbnail);
}
#Override
public int getItemCount() {
return mData.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv_Name;
TextView tv_Rating;
TextView tv_Descip;
TextView tv_Category;
ImageView img_Thumbnail;
public MyViewHolder(View itemView) {
super(itemView);
tv_Name = itemView.findViewById(R.id.food_name);
tv_Rating = itemView.findViewById(R.id.rating);
tv_Descip = itemView.findViewById(R.id.desc);
tv_Category = itemView.findViewById(R.id.category);
img_Thumbnail = itemView.findViewById(R.id.thumbnail);
}
}
}
This is my model
Food Class
public class Food {
String Name;
String Images;
String Descrip;
String Rating;
String Categ;
public Food() {
}
public Food(String name, String images, String descrip, String rating, String categ) {
this.Name = name;
this.Images = images;
this.Descrip = descrip;
this.Rating = rating;
this.Categ = categ;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getImages() {
return Images;
}
public void setImages(String images) {
Images = images;
}
public String getDescrip() {
return Descrip;
}
public void setDescrip(String descrip) {
Descrip = descrip;
}
public String getRating() {
return Rating;
}
public void setRating(String rating) {
Rating = rating;
}
public String getCateg() {
return Categ;
}
public void setCateg(String categ) {
Categ = categ;
}
}
My mian activity
CategoryActivity Class
public class CategoriaActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<Food> dbObjects;
private RecyclerView.Adapter adapter;
private AlertDialog.Builder dialogBuilder;
private AlertDialog dialog;
TextView l_nombre,l_precio;
Button l_finalizar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_categoria);
recyclerView = findViewById(R.id.recycle_id);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
dbObjects = new ArrayList<>();
ParseQuery<ParseObject> query = ParseQuery.getQuery("Category");
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> objList, ParseException e) {
if (e == null) {
for (ParseObject obj : objList) {
Food food = new Food();
food.setName(obj.getString("Name"));
food.setDescrip(obj.getString("Descrip"));
food.setRating(obj.getString("Rating"));
food.setCateg(obj.getString("Categ"));
food.setImages(obj.getString("Images"));
dbObjects.add(food);
}
} else {
FancyToast.makeText(CategoriaActivity.this, "Error: " + e.getMessage(), FancyToast.LENGTH_SHORT, FancyToast.ERROR, true).show();
}
}
});
adapter = new CategoryRAdapter(this, dbObjects);
recyclerView.setAdapter(adapter);
FloatingActionButton fab = findViewById(R.id.shoppingFlot);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
carritopop();
}
});
}
private void carritopop() {
dialogBuilder = new AlertDialog.Builder(this);
View view = getLayoutInflater().inflate(R.layout.pop_cart,null);
l_finalizar = view.findViewById(R.id.l_finalizar);
l_finalizar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
pago();
}
});
dialogBuilder.setView(view);
dialog = dialogBuilder.create();
dialog.show();
}
private void pago() {
Intent intent = new Intent(CategoriaActivity.this, PagoActivity.class);
startActivity(intent);
}
}
I dont know whats wrong with the code, the recycle view aint working, it aint showing any items, i would really appreciate if someone could help me out and notice something wrong in my code
Call adapter.notifyDataSetChanged() in your query done callback, this will notify the adapter that the list has changed. This is happening because when you set the adapter, the list was empty as the query was running in background. Once it completes, you have to tell the adapter that new data has been added to list:
if (e == null) {
for (ParseObject obj : objList) {
...
}
adapter.notifyDataSetChanged();
}
Also, create your adapter before you send the query otherwise it may result in NullPointerException in case data is loaded before the next statement executes (highly unlikely but never hurts to be safe).
dbObjects = new ArrayList<>();
adapter = new CategoryRAdapter(this, dbObjects);
ParseQuery<ParseObject> query = ParseQuery.getQuery("Category");
I recommend you to use RxJava2 to user asynchronous methods, it's awesome... And about the problem, maybe your data is not ready when you're already creating the adapter with the ArrayList.
Try to move the recyclerView.setAdapter() to inside the FindCallback after create the Food Objects.

Creating chat activity with recyclerView

For my first non-trivial Android app, I am making an app that involves chat rooms. I am using the chat room activity to teach myself recyclerView, which isn't covered as extensively as the somewhat antiquated listView in reference materials. I think I'm close to having a working recyclerView and adapter that I built trying to translate some of the elements of a listView into a recyclerView, but I am having trouble actually making the messages appear in the recyclerView. What am I doing wrong?
Here is my chat room activity:
public class ChatRoomActivity extends AppCompatActivity {
private static final String TAG = "Chat Room Activity";
private String mRoomID;
private String mRoomName;
private String mDisplayName;
private ArrayList<String> mUsernames = new ArrayList<>();
private ArrayList<String> mMessages = new ArrayList<>();
private RecyclerView mRecyclerView;
private EditText mInputText;
private ImageButton mSendButton;
private DatabaseReference mDatabaseReference;
private ChatRecyclerViewAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat_room);
Log.d(TAG," onCreate: started.");
// identifies views
mInputText = findViewById(R.id.messageInput);
mSendButton = findViewById(R.id.sendButton);
//gets user display name from current user and gets Firebase reference
setupDisplayName();
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
// gets Google Place ID from shared preferences
SharedPreferences preferences = getSharedPreferences(PLACE_PREFS, 0);
mRoomID = preferences.getString(PLACE_ID_KEY, null);
mRoomName = preferences.getString(PLACE_NAME_KEY, null);
Toast.makeText(this, mRoomID + mRoomName, Toast.LENGTH_LONG).show();
// Creates listener to send the message when the "enter" button is pressed
mInputText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
sendMessage();
return true;
}
});
// Adds an OnClickListener to the sendButton to send a message
mSendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendMessage();
}
});
}
private void setupDisplayName() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
mDisplayName = user.getDisplayName();
}
private void sendMessage() {
// Grabs the text the user typed in and pushes the message to Firebase
String input = mInputText.getText().toString();
if (!input.equals("")) {
Log.d(TAG, "Message sent");
Message chat = new Message(input, mDisplayName);
mDatabaseReference.child(mRoomID + "_messages").push().setValue(chat);
mInputText.setText("");
}
}
private void initRecyclerView(){
Log.d(TAG, "initRecyclerView: init recyclerview" );
mRecyclerView = findViewById(R.id.chatRecyclerView);
mAdapter = new ChatRecyclerViewAdapter(this,mMessages,mUsernames,mRoomID,mDatabaseReference);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}
#Override
protected void onStart() {
super.onStart();
initRecyclerView();
}
#Override
protected void onStop() {
super.onStop();
mAdapter.cleanup();
}
}
And here is my adapter:
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder> {
private static final String TAG = "ChatRecyclerViewAdapter";
private ArrayList<String> mMessage = new ArrayList<>();
private ArrayList<String> mAuthor = new ArrayList<>();
private String mRoomID;
private Context mContext;
private DatabaseReference mDatabaseReference;
private ArrayList<DataSnapshot> mSnapshotList;
private ChildEventListener mListener = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
mSnapshotList.add(dataSnapshot);
notifyDataSetChanged();
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
public ChatRecyclerViewAdapter(Context mContext, ArrayList<String> mMessage, ArrayList<String> mAuthor, String mRoomID, DatabaseReference reference) {
this.mMessage = mMessage;
this.mAuthor = mAuthor;
this.mContext = mContext;
this.mRoomID = mRoomID;
mSnapshotList = new ArrayList<>();
mDatabaseReference = reference.child(mRoomID+"_messages");
mDatabaseReference.addChildEventListener(mListener);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_msg_row,parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Log.d(TAG,"onBindViewHolder called");
holder.message.setText(mMessage.get(position));
holder.author.setText(mAuthor.get(position));
}
#Override
public int getItemCount() {
return mMessage.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView author;
TextView message;
RelativeLayout singleMessageContainer;
public ViewHolder(View itemView) {
super(itemView);
author = itemView.findViewById(R.id.chatAuthor);
message = itemView.findViewById(R.id.chatMessage);
singleMessageContainer = itemView.findViewById(R.id.singleMessageContainer);
}
}
void cleanup() {
mDatabaseReference.removeEventListener(mListener);
}
}
The way you're inserting the records into ArrayList in onChildAdded() and retrieving it in onBindViewHolder() of RecyclerView adapter is totally wrong.
Why do you need to create an ArrayList of Firebase Datasnapshots? Use the Message class instead (you didn't post Message class structure in your question).
Alter the ChatRecyclerViewAdapter like this
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder> {
// private ArrayList<String> mMessage = new ArrayList<>(); // comment or remove this line
// private ArrayList<String> mAuthor = new ArrayList<>(); // comment or remove this line
private String mRoomID;
private Context mContext;
private DatabaseReference mDatabaseReference;
// private ArrayList<DataSnapshot> mSnapshotList; // comment or remove this line
private ArrayList<Message> messageList; // add this member
}
The constructor
public ChatRecyclerViewAdapter(Context mContext, ArrayList<String> mMessage, ArrayList<String> mAuthor, String mRoomID, DatabaseReference reference) {
// this.mMessage = mMessage; // comment or remove this line
// this.mAuthor = mAuthor; // comment or remove this line
this.mContext = mContext;
this.mRoomID = mRoomID;
messageList = new ArrayList<>(); // initialize messageList object
mDatabaseReference = reference.child(mRoomID+"_messages");
mDatabaseReference.addChildEventListener(mListener);
}
And inside onChildAdded() method.
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
// convert Datasnapshot into a Message object
Message mes = dataSnapshot.getValue(Message.class);
// add it to an ArrayList of Message
messageList.add(mes); // notice the changes
notifyDataSetChanged();
}
Inside onBindViewHolder() method
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
// get single Message object from ArrayList
Message mes = messageList.get(position); // notice the difference
// just assuming that you've getter methods in your Message class
// please look into your code
holder.message.setText(mes.getMessage());
holder.author.setText(mes.getAuthor());
}
In getCount() method
#Override
public int getItemCount() {
return messageList.size(); // return the size of the ArrayList
}
Note: The way you implemented Chat using Firebase and RecyclerView is totally wrong. You should use/handle Firebase event listeners in an Activity or Fragment instead of it in an Adapter.
Before going into advanced stuff in Android please learn basic things first. You really need to understand how Firebase and RecyclerView works in first place.
Looking at the code above, ChatRecyclerViewAdapter's getItemCount() method returns the size of the messages array (mMessage.size()). But, notifyDataSetChanged() is called after adding an item to the DataSnapshot arraylist.
You have to also add the message from the snapshot to the messages array for the list to update when you call notifyDataSetChanged().
Also, it is recommended that you avoid calling notifyDataSetChanged() in general for performance reasons. RecyclerView.Adapter has helper methods such as notifyItemInserted or notifyItemRangeInserted to notify the adapter about new additions to the list.

Android - Firebase - Send Users to Chat Room

Aim
Allowing the Users to access their selected Group Chat. Once the user clicks on the Group Chat name, they will be entered into that Group Chat.
Database Tree
As shown in the Database Tree, the Currently Signed In user will be shown a list of Group Chat names that have been created.
I have an Admin Account to create these Group Chats for the users.
The Android, Asia, and Europe group chats that are seen within the Database ARE NOT fixed variables. They are names. A newly Group Chat name could be "Earth".
Therefore there is no way of calling it by a variable other than calling it by the Node itself.
Screenshot of Application
List of Group Chats 2. Entering a Group Chat
Flow of Activities
GroupFragment ---> Chat Activity
GroupFragment <--- Chat Activity
Flow of Application
User--->LoginActivity--->UserActivity--->GroupFrag--->GroupChatActivity
At the (GroupFrag--->GroupChatActivity) The user must select a Group Chat name within the GroupFrag to enter the GroupChatActivity
The user must select a Group Chat name within the GroupFrag to enter the GroupChatActivity
Description
The users will be able to select a Group Chat name (from GroupFragment) and the app will bring the user into the Group Chat itself (into Chat Activity). The User will be able to go back to the GroupFragment and select another desired Group.
(Group Chat names are NOT FIXED -- They're not a node that can be called from)
Problem
I am unable to select the Group Chat names after it was prompt within the Fragment, which will then bring me to the Group Chat.
Group Fragment
#Override
public void onStart() {
super.onStart();
class GroupAdapter extends RecyclerView.Adapter<GroupAdapter.MyHolder> {
ArrayList<String> list;
public GroupAdapter(ArrayList<String> list) {
this.list = list;
}
#Override
public GroupAdapter.MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_groups, parent, false);
return new MyHolder(view);
}
#Override
public void onBindViewHolder(MyHolder holder, int position) {
holder.setText(list.get(position));
}
#Override
public int getItemCount() {
return list.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
public MyHolder(View itemView) {
super(itemView);
nameTextView = itemView.findViewById(R.id.groupChatNameTxt);
}
public void setText(String groupName) {
nameTextView.setText(groupName);
}
}
}
jGroupsDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ArrayList<String> groupChatNames = new ArrayList<>();
for (DataSnapshot child : dataSnapshot.getChildren()) {
groupChatNames.add(child.getKey());
}
GroupAdapter adapter = new GroupAdapter(groupChatNames);
jGroupChatList.setAdapter(adapter);
//I'm not sure where to write a code for userID
//final String usersID = getRef(position).getKey();
// When the user clicks on one of the group chat names, he/she will be sent to the Chat Activity
jGroupChatList.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intentUserProfile = new Intent(getActivity(), ChatActivity.class);
intentUserProfile.putExtra("groupChatName",groupName);
intentUserProfile.putExtra("neighbourhood", neighbourhood);
intentUserProfile.putExtra("usersName", usersName);
intentUserProfile.putExtra("usersID", usersID);
startActivity(intentUserProfile);
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Chat Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
jGroupChatName = getIntent().getExtras().get("groupChatName").toString();
jUserID = getIntent().getExtras().get("usersID").toString();
jUserName = getIntent().getExtras().get("usersName").toString();
jUserNeighbourhood = getIntent().getExtras().get("neighbourhood").toString();
jChatRoot = FirebaseDatabase.getInstance().getReference().child(jGroupChatName);
jChatToolbar = (Toolbar) findViewById(R.id.allUSersToolBar);
setSupportActionBar(jChatToolbar);
getSupportActionBar().setTitle(jGroupChatName); // Show the name of the selected group name
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
Additional Comments
Online Tutorial
I have watched an Android Firebase Group Chat tutorial on youtube. The link is https://www.youtube.com/watch?v=wVCz1a3ogqk. But it does not provide some the features/ functions whic I am trying to implement.
Linked Question
Android - Firebase - Prompting Group Chat Names
Future Implementations
For future implementations, I would like to send and retrieve the messages and prompt it into the group chat for the users to view like a real group chat. But of course, I will leave that for another Question.
You can update your adapter and viewholder implementation as follows:
public class Adapter extends RecyclerView.Adapter<Adapter.MyHolder> {
Context context;
ArrayList<String> list;
public Adapter(Context context, ArrayList<String> list) {
this.context = context;
this.list = list;
}
#Override
public Adapter.MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_groups, parent, false);
MyHolder holder = new MyHolder(view);
return holder;
}
#Override
public void onBindViewHolder(MyHolder holder, int position) {
holder.setText(list.get(position));
}
#Override
public int getItemCount() {
return list.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
String groupName = list.get(getAdapterPosition());
Intent intentUserProfile = new Intent(context, MainActivity.class);
intentUserProfile.putExtra("groupChatName", groupName);
// If fixed, you should pass these values to adapter's constructor
// intentUserProfile.putExtra("neighbourhood", neighbourhood);
// intentUserProfile.putExtra("usersName", usersName);
// intentUserProfile.putExtra("usersID", usersID);
context.startActivity(intentUserProfile);
}
};
public MyHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(onClickListener);
nameTextView = (TextView) itemView.findViewById(R.id.groupChatNameTxt);
}
public void setText(String groupName) {
nameTextView.setText(groupName);
}
}
}
You also have to update this line in your GroupFragment:
GroupAdapter adapter = new GroupAdapter(getActivity(), groupChatNames);
This is another solution that you can implement inside your fragment so that you can put extras in intent (actually modified from your former question):
#Override
public void onStart() {
super.onStart();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference groupChatsRef = rootRef.child("Group Chats");
FirebaseRecyclerAdapter<String, GroupChatViewHolder> chatAdapter = new FirebaseRecyclerAdapter<String, GroupChatViewHolder>(
String.class,
R.layout.layout_groups,
GroupChatViewHolder.class,
groupChatsRef) {
protected void populateViewHolder(GroupChatViewHolder viewHolder, String model, int position) {
final String groupChatName = this.getRef(position).getKey();
viewHolder.setName(groupChatName);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intentUserProfile = new Intent(getActivity(), ChatActivity.class);
intentUserProfile.putExtra("groupChatName", groupChatName);
intentUserProfile.putExtra("neighbourhood", neighbourhood);
intentUserProfile.putExtra("usersName", usersName);
intentUserProfile.putExtra("usersID", usersID);
startActivity(intentUserProfile);
}
});
}
};
jGroupChatList.setAdapter(chatAdapter);
}
Note that it handles your string-string group chat entries in your DB as key-value pairs.
public class group_name_list_adapter extends RecyclerView.Adapter<group_name_list_adapter.ViewHolder> {
private List< group_name_list> listItems;
private Context context;
OnItemClickListener onItemClickListener;
public group_name_list_adapter(List<group_name_list> listItems, Context context) {
this.listItems = listItems;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.group_name_list, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
group_name_list listItem = listItems.get(position);
holder.txtTitle.setText(listItem.getTxtTitle());
holder.txtTitle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemClickListener.onGroupNameClick(position);
}
});
}
#Override
public int getItemCount() {
return listItems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView txtTitle;
public ViewHolder(View itemView) {
super(itemView);
txtTitle = (TextView) itemView.findViewById(R.id.txtTitle);
}
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
public interface OnItemClickListener{
void onGroupNameClick(int position);
}
}
public class group_name_list {
private String txtTitle;
public group_name_list(String txtTitle) {
this.txtTitle = txtTitle;
}
public String getTxtTitle() {
return txtTitle;
}
}
public class ChatActivity implements group_name_list_adapter.OnItemClickListener
private RecyclerView recyclerGroupName;
private group_name_list_adapter groupNameAdapter;
private List<group_name_list> group_name_List;
private List<String> groupNameKeyList; //This is optional – this is used if you wanted the group chats to have the same name instead of overwriting the groupchat when creating.
Inside your Firebase call:
group_name_List.removeAll(group_name_List t);
groupNameKeyList.removeAll(groupNameKeyList);
//Depending on your firebase reference. This could just be dataSnapshot.getChildren()
for (DataSnapshot child : dataSnapshot.child("Group Chats").getChildren()){
if (!child.getKey().equals(null)){
groupNameKeyList.add(child.getKey().toString()); //Again this is optional
}
group_name_list newGroupList = child.getValue();
);
groupNameList.add(newGroupList);
}
recyclerGroupName.setAdapter(groupNameAdapter);
gLayoutAttribute = new GridLayoutManager(getActivity(), 1);
recyclerGroupName = (RecyclerView) rootView.findViewById(R.id.recyclerGroupName);
recyclerGroupName.setHasFixedSize(true);
recyclerGroupName.setLayoutManager(new LinearLayoutManager(this.getContext()));
recyclerGroupName.setLayoutManager(gLayoutAttribute);
#Override
public void onAttributeClick(int position) {
Intent intentUserProfile = new Intent(getActivity(), ChatActivity.class);
intentUserProfile.putExtra("groupChatName",groupName);
intentUserProfile.putExtra("neighbourhood", neighbourhood);
intentUserProfile.putExtra("usersName", usersName);
intentUserProfile.putExtra("usersID", usersID);
intent.putExtra("name", groupList.get(position).toString());
//intent.putExtra("name", groupListKeyList.get(position).toString()); this is your optional key
startActivity(intentUserProfile);
}
Try according to this
Suppose you've created 5 user's in FirebaseDatabasewith different UID's
In this step you have to get all user's from Firebase and display it in RecyclerView
In Recyclerview's adapter class in onBindViewHolder' you have to do like add and remove` users from list which you generated at the time creating group.
In this step you've to search firebaseDatabase user's Uid which is currently logged in and if your UID is matched found in any Group then you need to get the Group-name .
Happy to help you

Categories

Resources