Creating chat activity with recyclerView - java

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.

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.

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

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);

Download only part of Database reference in Firebase?

I have a chat app as part of my Android app that stores all messages in a chat room under a Firebase database reference that carries the ID number for that room. As it stands, the RecyclerView that holds the messages in the chat Activity downloads all messages in that room whenever the user enters it, consuming a potentially unwieldy amount of data. How should I go about making it only download the X most recent messages and download X more if the user scrolls to top?
Here is my adapter:
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder> {
private static final String TAG = "ChatRecyclerViewAdapter";
private String mRoomID;
private Context mContext;
private DatabaseReference mDatabaseReference;
private ArrayList<Message> messageList;
private ChildEventListener mListener = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
// Convert data snapshot from Database into a Message Object
Message message = dataSnapshot.getValue(Message.class);
// Add it to an arrayList of Messages
messageList.add(message);
// Notice Changes
notifyItemInserted(messageList.size());
}
#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.mContext = mContext;
this.mRoomID = mRoomID;
messageList = new ArrayList<>();
mDatabaseReference = reference.child(mRoomID+"_messages");
mDatabaseReference.addChildEventListener(mListener);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//This method loads layout(fields) of ViewHolder
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) {
// This method fills fields with data for each list item
Log.d(TAG,"onBindViewHolder called");
Message message = messageList.get(position);
holder.message.setText(message.getMessage());
holder.author.setText(message.getAuthor()+":");
}
#Override
public int getItemCount() {
return messageList.size();
}
//Viewholder stores the information about the layout and content of each list item, and serves as a template for each item of a RecyclerView
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);
}
}
If the messages are stored chronologically already (e.g. if you use push() to add them), you can order the messages by their key and get the most recent ones with:
mDatabaseReference = reference.child(mRoomID+"_messages");
Query recentMessages = mDatabaseReference.orderByKey().limitToLast(10);
recentMessages.addChildEventListener(mListener);
As Doug commented, please check the Firebase documentation on queries for more options

Value Event Listener Returns Null

My Datastructure
I am trying to get the TeacherId from the teacher with the same email of the currently logged in teacher from my database.Then store it to a string variable then later pass it to an adapter class for querying again. but everytime I try to retrieve it using ValueEventListener it returns null.
My Code
public class SchedList extends AppCompatActivity {
//member vars. ui objects
public ListView SubSchedListView;
public TextView schedList;
public TextView tIDTextView;
//data vars
private String email;
private String teacherid;
private ArrayList<DataSnapshot> snapshot;
//classes
private TeacherAccount ta;
private subjSchedAdapter mAdapter;
//
private DatabaseReference mDatabaseReference;
private SharedPreferences prefs;
//listener
private String x;
private String y;
private String z;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sched_list);
mDatabaseReference = FirebaseDatabase.getInstance().getReference().child("teacheraccount").child("TeacherId");
//ui objects
SubSchedListView = (ListView) findViewById(R.id.SubSchedListView);
schedList = (TextView) findViewById(R.id.schedTextView);
tIDTextView = (TextView) findViewById(R.id.tIDTextView);
//data vars
Intent intent = new Intent();
email = intent.getStringExtra("email");
snapshot = new ArrayList<>();
}
#Override
public void onStart() {
super.onStart();
Intent intent = new Intent();
Query query = mDatabaseReference.orderByChild("Email").equalTo(intent.getStringExtra("email"));
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ta = dataSnapshot.getValue(TeacherAccount.class);
x = ta.getTeacherId(); //the part where it says it returns null
y = dataSnapshot.getValue(String.class);
if (dataSnapshot.getKey().equals("TeacherId")) {
z = dataSnapshot.getValue(String.class);
}
Log.d("WHICH_HAS", x + y + z);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
// Setting the adapter
Log.d("WHICH_HAS", x + y + z);
//mAdapter = new subjSchedAdapter(this, mDatabaseReference,teacherid);
SubSchedListView.setAdapter(mAdapter);
}
#Override
public void onStop() {
super.onStop();
mAdapter.cleanup();
}
}
At which part is there something wrong ? should the valueListener be in the Onstart ? OnCreate ? or on its own function ? if so, at which part do I call the function ? at what other parts did I do wrong at ?
How do you pass a string data to a base adapter class ?
My Base Adapter class
public class subjSchedAdapter extends BaseAdapter{
private Activity mActivity;
private DatabaseReference mDatabaseReference;
private String mTeacherId;
private ArrayList<DataSnapshot> mSnapshotList;
private Query query;
private Context mContext;
// child event listener
private ChildEventListener mListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
mSnapshotList.add(dataSnapshot);
notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
mSnapshotList.add(dataSnapshot);
notifyDataSetChanged();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
//constructor
public subjSchedAdapter(Activity activity, DatabaseReference ref, String id){
mActivity = activity;
//mTeacherId = subjteacherid;
mDatabaseReference = ref.child("subjects");
//this is where id = the teacherId I retrieved
query = mDatabaseReference.orderByChild("teacherid").equalTo(id).limitToFirst(1);
query.addChildEventListener(mListener);
mSnapshotList = new ArrayList<>();
}
//view holder
static class ViewHolder{
TextView subjectCodeAndName;
TextView time;
TextView sectionName;
TextView teacherId;
LinearLayout.LayoutParams params;
}
#Override
public int getCount() {
return mSnapshotList.size();
}
#Override
public SubjectScheds getItem(int position) {
DataSnapshot snapshot = mSnapshotList.get(position);
return snapshot.getValue(SubjectScheds.class);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.subject_sched_list, parent, false);
final ViewHolder holder = new ViewHolder();
holder.subjectCodeAndName = (TextView) convertView.findViewById(R.id.subjectCodeAndName);
holder.time = (TextView) convertView.findViewById(R.id.time);
holder.sectionName = (TextView) convertView.findViewById(R.id.sectionName);
holder.teacherId = (TextView) convertView.findViewById(R.id.teacherid);
holder.params = (LinearLayout.LayoutParams) holder.subjectCodeAndName.getLayoutParams();
convertView.setTag(holder);
}
final SubjectScheds subjectsched = getItem(position);
final ViewHolder holder = (ViewHolder) convertView.getTag();
String subjcodeandname = subjectsched.getSubjectCode() + " - " + subjectsched.getSubjectName();
String time = "time : " + subjectsched.getTime();
String sectionName = "section : " + subjectsched.getSectionname();
String teacherId = "teacher : " + subjectsched.getTeacherid();
holder.subjectCodeAndName.setText(subjcodeandname);
holder.time.setText(time);
holder.sectionName.setText(sectionName);
holder.teacherId.setText(teacherId);
return convertView;
}
public void cleanup(){
mDatabaseReference.removeEventListener(mListener);
}
}
The part in the code where I set the adapter
Method Call
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot finalSnap :dataSnapshot.getChildren()){
ta = finalSnap.getValue(TeacherAccount.class);
x = ta.getTeacherId(); //the part where it says it returns null
tIDTextView.setText(x);
Display(x);
}
}
Method
private void Display(String x){
mAdapter = new subjSchedAdapter(this,mDatabaseReference,x);
SubSchedListView.setAdapter(mAdapter);
}
You have got the wrong database reference if you want to OrderbyChiled by Email then you want to get the reference to the parent of that specific field.
As per your case you need to find reference to teacher account as per follow:
mDatabaseReference = FirebaseDatabase.getInstance().getReference().child("teacheraccount");

Android - How to handle multiple Elements in a singe ListViewItem?

i have a specific issue. Im creating a App which allows me to display recepts of certain dishes. I designed a custom Adapter which contains a TextView and RatingBar. So in my other Activity(ViewDatabase) i retrieve the dish-name from a JSON-File (method is called : showData) and display it on a ListView which gets the custom adapter.
My problem is now that dont know why i can only select either the name of my dish ( so the textview of my adapter ) or the ratingbar ( is also in my adapter).
I tried to put in the method : myListView.setItemsCanFocus(true); but still doesnt work.
Is i didnt implement a clicklistener to my text in the Adapter? I tried to implement one.I need a explicit intent which swaps the Activity but i cant
go from a Adapterclass to a other class in a intent.
In the ViewDatabse- Class is onItemClick my method for changing the activty if i click the text.
Here is my code :
Adapter:
a)
public UserInformationAdapter(Context context, List<UserInformation> objects) {
super(context, R.layout.rating_item, objects);
this.context = context;
table = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.rating_item, null);
}
TextView name = (TextView) v.findViewById(R.id.hauptgerichte);
RatingBar ratingBar = (RatingBar) v.findViewById(R.id.rate_bar);
UserInformation userInformation = table.get(position);
ratingBar.setOnRatingBarChangeListener(onRatingChangedListener(position));
ratingBar.setTag(position);
ratingBar.setRating(getItem(position).getRatingStar());
name.setText(userInformation.getName());
name.setTag(position);
return v;
}
private RatingBar.OnRatingBarChangeListener onRatingChangedListener(final int position) {
return new RatingBar.OnRatingBarChangeListener() {
#Override
public void onRatingChanged(RatingBar ratingBar, float v, boolean b) {
UserInformation item = getItem(position);
assert item != null;
item.setRatingStar(v);
Log.i("Adapter", "star: " + v);
}
};
}
}
This is the Item (for name and ratingbar):
public class UserInformation {
private String name;
private float ratingStar;
public UserInformation(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
void setRatingStar(float ratingStar) {
this.ratingStar = ratingStar;
}
float getRatingStar() {
return 0;
}
#Override
public String toString(){
return name;
}
}
This is the Activity which retrieves the Name:
Activity:
public class ViewDatabase extends AppCompatActivity {
private static final String TAG = "ViewDatabase";
private FirebaseDatabase mFirebaseDatabase;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private DatabaseReference myRef;
private String userID;
private ArrayList<String> array;
private final List<UserInformation> arr = new ArrayList<>();
private UserInformationAdapter adapter2;
private ListView mListView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_database_layout);
array = new ArrayList<>();
mListView = (ListView) findViewById(R.id.list_karnivoure);
mListView.setItemsCanFocus(true);
mAuth = FirebaseAuth.getInstance();
mFirebaseDatabase = FirebaseDatabase.getInstance();
myRef = mFirebaseDatabase.getReference();
FirebaseUser user = mAuth.getCurrentUser();
userID = user.getUid();
myRef.child("shakes").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
showData(dataSnapshot);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void showData(DataSnapshot dataSnapshot) {
Iterable<DataSnapshot> children = dataSnapshot.getChildren();
for (DataSnapshot child: children){
UserInformation uInfo = child.getValue(UserInformation.class);
arr.add(uInfo);
adapter2 = new UserInformationAdapter(ViewDatabase.this, arr);
mListView.setAdapter(adapter2);
mListView.setItemsCanFocus(true);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mListView.setItemsCanFocus(true);
Object listItem = mListView.getItemAtPosition(position);
Intent i = new Intent(ViewDatabase.this,KarnivoureInput.class);
i.putExtra("name", listItem.toString());
startActivity(i);
}
});
}
https://stackoverflow.com/a/8955441/5608931
Try adding this attribue to TextView and RatingBar . It would be clickable but will not get Focused
android:focusable="false"

Categories

Resources