I am attempting to implement my own CardView within a Fragment following previous help from another SO user. I think I have done everything correctly however I am not seeing the expected results and think the fault is elsewhere..
What I have is a CalendarView within a Fragment which displays the selected date inside a TextView using setOnDateChangeListener. I then have a hidden RecyclerView which has a CardView within that, which I am trying to call if the CalendarView date matches the date stored in my Firebase database.. Still with me?
I am creating an event schedule, using a form which has event name, date, time, description, all stored as strings, see below:
I have no idea how to retrieve the push() value when referencing my database so I have just used the event name for ease at the moment..
Here is what I have, it is a bit all over the place as I have been testing here and there but please let me know if you have questions.. I tried separating my database references to use them in different areas but this did not work either.
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_schedule, container, false);
intentEvent = getActivity().getIntent().getStringExtra("name");
// ------------- firebase --------------
firebaseAuth = FirebaseAuth.getInstance();
currentUser = firebaseAuth.getCurrentUser();
uid = currentUser.getUid();
databaseReference = FirebaseDatabase.getInstance().getReference("user").child(uid).child("dogs").child(intentEvent);
eventReference = databaseReference.child("events");
dateRef = eventReference.child("date");
// -------------------------------------
calendarView = view.findViewById(R.id.calendarView);
scheduleTitle = view.findViewById(R.id.scheduleTitle);
noEventPlaceholder = view.findViewById(R.id.noEventPlaceholder);
addNewEvent = view.findViewById(R.id.addNewEvent);
eventRecycler = view.findViewById(R.id.eventRecycler);
eventRecycler.setVisibility(View.GONE);
eventLayoutManager = new LinearLayoutManager(getContext());
eventRecycler.setLayoutManager(eventLayoutManager);
FirebaseRecyclerOptions<Event> options
= new FirebaseRecyclerOptions.Builder<Event>()
.setQuery(databaseReference, Event.class)
.build();
eventAdapter = new EventAdapter(options, new EventAdapter.EventCallback() {
#Override
public void onCardViewClick(Event event) {
// view event in full?
}
});
if (eventReference == null) {
addNewEvent.setVisibility(View.VISIBLE);
noEventPlaceholder.setText("Nothing planned for today.. Let's go walkies!");
} else {
eventRecycler.setVisibility(View.VISIBLE);
}
eventRecycler.setAdapter(eventAdapter);
getEventData();
dog = new Dog();
calendarView
.setOnDateChangeListener(
new CalendarView
.OnDateChangeListener() {
#Override
public void onSelectedDayChange(
#NonNull CalendarView view,
int year,
int month,
int dayOfMonth)
{
String date
= dayOfMonth + "-"
+ (month + 1) + "-" + year;
scheduleTitle.setText(date);
}
});
// this is an example of what i am trying to do..
if (String.valueOf(dateRef).equals(scheduleTitle)) {
eventRecycler.setVisibility(View.VISIBLE);
noEventPlaceholder.setText("Nothing planned for today.. Let's go walkies!");
}
// ---------------------------------------------
addNewEvent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String name = dataSnapshot.child("name").getValue(String.class);
Intent intentEventForm = new Intent(getContext(), EventForm.class);
intentEventForm.putExtra("name", name);
startActivity(intentEventForm);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w("TAG", "onCancelled", databaseError.toException());
}
});
}
});
return view;
}
public void getEventData() {
eventReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String eventName = dataSnapshot.child("name").getValue(String.class);
String eventDate = dataSnapshot.child("date").getValue(String.class);
String eventTime = dataSnapshot.child("time").getValue(String.class);
String eventDescription = dataSnapshot.child("description").getValue(String.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w("TAG", "onCancelled", databaseError.toException());
}
});
}
Related
I have this code which retrieves the information I need from the firebase database:
private void getname(){
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
Query lastQuery = ref.child("ride_info").orderByKey().limitToLast(1);
lastQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()){
String value0_float = ds.child("pickup").child("name").getValue(String.class);
pickupName = String.valueOf(value0_float);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
and i have this:
public String getPickupName() {
getname();
String s = String.valueOf(pickupName);
return s;
}
All of the above code is in the RideObject class.
This is the code there is in CardRequestAdapter Class to display the String in the textview mPickupName:
public View getView(int position, View convertView, ViewGroup parent){
RideObject card_item = getItem(position);
if (convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item__card_request, parent, false);
}
TextView mDistance = convertView.findViewById(R.id.distance);
TextView mTime = convertView.findViewById(R.id.time);
CircularProgressBar mProgressBar = convertView.findViewById(R.id.circularProgressBar);
mDistance.setText(card_item.getPickupName());
mTime.setText(card_item.getCalculatedTime() + " min");
final Handler ha=new Handler();
ha.postDelayed(new Runnable() {
#Override
public void run() {
//call function
card_item.setTimePassed(card_item.getTimePassed() + (float)0.5);
mProgressBar.setProgress(card_item.getTimePassed());
if(card_item.getTimePassed() > 100){
items.remove(card_item);
notifyDataSetChanged();
}
ha.postDelayed(this, 50);
}
}, 50);
return convertView;
}
}
The problem I have is that I cannot get the name I got from the Firebase database. Why is nothing displayed in the text view?
Data is loaded from Firebase asynchronously, since it may take some time. If you set some breakpoints or add some logging you'll likely see that mDistance.setText(card_item.getPickupName()); runs before pickupName = String.valueOf(value0_float), which means you're setting an empty string into the text view.
The rule to fix/prevent this is simple: any code that needs data from the database needs to be inside onDataChange or be called from there.
So something like:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
Query lastQuery = ref.child("ride_info").orderByKey().limitToLast(1);
lastQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()){
String value0_float = ds.child("pickup").child("name").getValue(String.class);
pickupName = String.valueOf(value0_float);
mDistance.setText(pickupName);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});
Also see:
getContactsFromFirebase() method return an empty list
I have a fire node by the name of myHire which has a child which is identified by the current user id (whoever is logged in), The child further below the current user id node is the PostNode which can be anything and below postnode, lies the id,s of all those people who are interacting with the post. the postnode id and peopleInvolvedNode id in the postnode are not known to me by some specific identifier so i am trying to retreive their keys and values using ValueEventListener/onDataChange loop. my problem arises when the the loop only retrieve the last node child and ignored the all the node which are above.
I am trying to solve this from a very long time. So any help would be appreciated
Thank You and have a nice day
This is my database structure to help understanding the question precisely
Below is my code
myHire = FirebaseDatabase.getInstance().getReference().child("My Hire").child(currentUserID);
myHire.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot child1 : dataSnapshot.getChildren()) {
String checkKeys1 = child1.getKey();
Query query = myHire.child(checkKeys1);
FirebaseRecyclerOptions<hiredListDetails> options = new FirebaseRecyclerOptions.Builder<hiredListDetails>()
.setQuery(query, hiredListDetails.class).build();
final FirebaseRecyclerAdapter<hiredListDetails, MyViewHolder> adapter =
new FirebaseRecyclerAdapter<hiredListDetails, MyViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final MyViewHolder holder, int position, #NonNull final hiredListDetails model) {
Log.d(TAG, "onBindViewHolder: call 4");
holder.topic.setText(model.getWorktitle());
Log.d(TAG, "onBindViewHolder: the topic is "+model.getWorktitle());
holder.hiredPersonName.setText(model.getHiredpersonname());
holder.hiredPersonBidPrice.setText(model.getHiredpersonprice() + " BD");
String givenDateString = model.getCurrentdateandtime();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy, HH:mm");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Bahrain"));
long timeInMilliseconds = 0;
try {
Date mDate = sdf.parse(givenDateString);
timeInMilliseconds = mDate.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
final CharSequence ch = DateUtils.getRelativeTimeSpanString(timeInMilliseconds, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS);
holder.timeAgo.setText(ch);
Picasso.get().load(model.getHiredpersonimage()).placeholder(R.drawable.profile)
.into(holder.hiredPersonPic);
holder.requestTracker.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String clickedRecyclerKey = getRef(holder.getAdapterPosition()).getKey();
Log.d(TAG, "onClick: clicked Recycler key is " + clickedRecyclerKey);
String checkStatusForTracking = model.getActivatelocation();
if (checkStatusForTracking.equalsIgnoreCase("True")) {
Intent intent = new Intent(getContext(), TrackUserMap.class);
startActivity(intent);
} else {
getLocationRequest(clickedRecyclerKey);
Toast.makeText(getContext(), "Please wait while the tracking process is completed",
Toast.LENGTH_LONG).show();
}
}
});
String checkStatusForTracking = model.getActivatelocation();
if (checkStatusForTracking.equalsIgnoreCase("Request")) {
holder.requestTrackerStatusMark.setImageDrawable(getResources().getDrawable(R.drawable.statusyellow));
} else if (checkStatusForTracking.equalsIgnoreCase("True")) {
holder.requestTrackerStatusMark.setImageDrawable(getResources().getDrawable(R.drawable.statusgreen));
}
loadingBar.dismiss();
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.hired_individual_row_layout, parent, false);
MyViewHolder viewHolder = new MyViewHolder(view);
return viewHolder;
}
};
myHiredList.setAdapter(adapter);
adapter.startListening();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
My Firebase database is like that -
users -
first user ID
- name - "abc"
- image - "url"
- one_word - "abc"
following -
first user ID -
second User ID - "0"
Following node shows that First user is following second user.
Here is my code -
#Override
protected void onStart() {
super.onStart();
imageView.setVisibility(View.GONE);
FirebaseRecyclerAdapter<followers_following_class,following_Adapter>firebaseRecyclerAdapter =
new FirebaseRecyclerAdapter<followers_following_class, following_Adapter>
(
followers_following_class.class,
R.layout.find_friend_card,
following_Adapter.class,
databaseReference
) {
#Override
protected void populateViewHolder(final following_Adapter viewHolder, final followers_following_class model, int position) {
final String user_id = getRef(position).getKey();
users.child(user_id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
final String name = dataSnapshot.child("name").getValue().toString();
final String image = dataSnapshot.child("image").getValue().toString();
final String line = dataSnapshot.child("line").getValue().toString();
final String wins = dataSnapshot.child("one_word").getValue().toString();
viewHolder.setName(name);
viewHolder.setImage(following.this,image);
viewHolder.setLine(line);
viewHolder.setOne_word(wins);
if(getItemCount() == 0){
imageView.setVisibility(View.VISIBLE);
}
viewHolder.vieww.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!user_id.equals(my_id)){
Intent intent = new Intent(following.this,Friend_profile_view.class);
intent.putExtra("user_id",user_id);
intent.putExtra("image",image);
intent.putExtra("one_word",wins);
intent.putExtra("name",name);
startActivity(intent);
}
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
};
list.setAdapter(firebaseRecyclerAdapter);
}
public static class following_Adapter extends RecyclerView.ViewHolder {
View vieww;
public following_Adapter(View itemView) {
super(itemView);
this.vieww = itemView;
}
public void setImage( final following following, final String image) {
final CircleImageView circleImageView = (CircleImageView)vieww.findViewById(R.id.find_friend_profile_image_card);
if(!image.equals("default_image")) {
Picasso.with(following).load(image).networkPolicy(NetworkPolicy.OFFLINE).into(circleImageView, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
Picasso.with(following).load(image).into(circleImageView);
}
});
}
}
public void setName(String name) {
TextView textView = (TextView)vieww.findViewById(R.id.find_friends_name_card);
textView.setText(name);
}
public void setLine(String line) {
ImageView imageView = (ImageView)vieww.findViewById(R.id.online_or_not);
if(line.equals("offline")){
imageView.setVisibility(View.INVISIBLE);
}
}
public void setOne_word(String wins) {
TextView textView = (TextView)vieww.findViewById(R.id.user_level);
textView.setText(wins);
}
}
Is there any way where i can apply firebase recycler adapter for one node but retrieve data form another node with same key without using addValueEventListener ?
And also most of my app uses firebase recyclerview in all activities so when i observed my android profiler , my RAM usage is increasing while switching between activities i have also used finish(); ended the addValuelistener in onDistroy method but it is still not working.
There are 3 eventListeners that you can use according to your needs, namely valueEventListener, childEventListener and singleValueEventListener.
This will be a good read for this, Firebase Docs.
When working with lists, your application should listen for child events rather than the value events used for single objects.
Child events are triggered in response to specific operations that happen to the children of a node from an operation such as a new child added through the push() method or a child being updated through the updateChildren() method. Each of these together can be useful for listening to changes to a specific node in a database.
In code, childEventListener looks like this:
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
// A new comment has been added, add it to the displayed list
Comment comment = dataSnapshot.getValue(Comment.class);
// ...
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
// A comment has changed, use the key to determine if we are displaying this
// comment and if so displayed the changed comment.
Comment newComment = dataSnapshot.getValue(Comment.class);
String commentKey = dataSnapshot.getKey();
// ...
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
// A comment has changed, use the key to determine if we are displaying this
// comment and if so remove it.
String commentKey = dataSnapshot.getKey();
// ...
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
// A comment has changed position, use the key to determine if we are
// displaying this comment and if so move it.
Comment movedComment = dataSnapshot.getValue(Comment.class);
String commentKey = dataSnapshot.getKey();
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "postComments:onCancelled", databaseError.toException());
Toast.makeText(mContext, "Failed to load comments.",
Toast.LENGTH_SHORT).show();
}
};
ref.addChildEventListener(childEventListener);
Also, retrieving data without the use of eventListeners is not possible. And if you want to listen to children of your one node, simultaneously, then childEventListener will be a great tool.
I have recently managed to make a custom listview layout and populate that data from a listview.
The listview contains a "Like" Button and a textview storing the amount of likes. Yet i cant seem to figure out how to take that int and increment it on button press as the will be performed in the CustomAdapter.
Data Model:
public class MessagesListDataModel {
private String uid;
private String msg;
private String likes;
private String date;
private Button like;
private Button reply;
public MessagesListDataModel(String uid, String msg, String date) {
this.uid = uid;
this.msg = msg;
this.date = date;
this.likes = likes;
}
public MessagesListDataModel(){
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getLikes() {
return likes;
}
public void setLikes(String likes) {
this.likes = likes;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public Button getLike() {
return like;
}
public void setLike(Button like) {
this.like = like;
}
}
The Adapter:
public class MessagesListAdapter extends ArrayAdapter<MessagesListDataModel> {
private ArrayList<MessagesListDataModel> dataModels;
public MessagesListAdapter(Context context, ArrayList<MessagesListDataModel> dataModels){
super(context,0, dataModels);
this.dataModels = dataModels;
}
/*
* we are overriding the getView method here - this is what defines how each
* list item will look.
*/
public View getView(int position, View convertView, ViewGroup parent){
MessagesListDataModel messagesListDataModel = dataModels.get(position);
// first check to see if the view is null. if so, we have to inflate it.
// to inflate it basically means to render, or show, the view.
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.chat_messages_layout, parent, false);
}
TextView uid = (TextView) convertView.findViewById(R.id.textViewUserID);
TextView message = (TextView) convertView.findViewById(R.id.textViewMessage);
TextView likes = (TextView) convertView.findViewById(R.id.textViewLikes);
TextView date = (TextView) convertView.findViewById(R.id.textViewDateTime);
Button like = (Button) convertView.findViewById(R.id.buttonLike);
Button reply = (Button) convertView.findViewById(R.id.buttonReply);
uid.setText(messagesListDataModel.getUid());
message.setText(messagesListDataModel.getMsg());
date.setText(messagesListDataModel.getDate());
likes.setText(messagesListDataModel.getLikes());
like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast toast = Toast.makeText(getContext(), "Like button pressed", Toast.LENGTH_SHORT);
toast.show();
//Increment the value of the likes textview and reload that textview to display new likes. Limit the likes to only be able to like a post once.
}
});
reply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast toast = Toast.makeText(getContext(), "reply button pressed", Toast.LENGTH_SHORT);
toast.show();
//passing data for the reference in the replies class.
}
});
return convertView;
}
}
In the like.SetOnClickListener, how can i retrieve data from firebase database stored as "likes", update the int by adding 1 and store it back into the database?
Can this even be done in the adapter or does this need to take place in the "main activity" of where the data gets populated? Im not sure how to go about this.
Also another problem is that the textviews dont accept Int's so i need to be converting from string to int and back when doing this?
Main Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat_room);
//for sending messages to database
btn_send_msg = (Button) findViewById(R.id.btn_send);
input_msg = (EditText) findViewById(R.id.msg_Input);
//Date time
//DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
//dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
//Date date = new Date();
//String dtSent = ((dateFormat.format(date).toString()));
//UserData student ID
FirebaseUser loggedinFirebaseUser = FirebaseAuth.getInstance().getCurrentUser();
String userId = loggedinFirebaseUser.getUid();
room_name = getIntent().getExtras().get("room_name").toString();
setTitle(" Room - " + room_name);
//stores the reference as a string to be passed onto the userDataReference table
databaseUrlRef = "users/userData" + "/" + userId;
userDataRef = FirebaseDatabase.getInstance().getReference(databaseUrlRef + "/SID");
chatroomsref = FirebaseDatabase.getInstance().getReference("Chatrooms").child(room_name);
///////
final MessagesListAdapter arrayAdapter = new MessagesListAdapter(this,arrayMessages);
ListViewMessages = (ListView) findViewById(R.id.chatRoomMessagesListview);
ListViewMessages.setAdapter(arrayAdapter);
chatroomsref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
//fetchData();
//for (DataSnapshot child : dataSnapshot.getChildren()) {
MessagesListDataModel messagesListDataModel =
dataSnapshot.getValue(MessagesListDataModel.class);
arrayMessages.add(messagesListDataModel);
arrayAdapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
/////
//reference to the database that is within the chatrooms and the room name of the name that was clicked and passed onto this activity.
root = FirebaseDatabase.getInstance().getReference("Chatrooms/" + room_name);
userDataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String Name = dataSnapshot.getValue().toString();
user_name = Name;
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//https://stackoverflow.com/questions/40891268/how-to-get-firebase-data-into-a-listview
btn_send_msg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String dtSent = ((dateFormat.format(date).toString()));
Map<String, Object> map = new HashMap<String, Object>();
temp_key = root.push().getKey();
// temp key is the randomly generated key
root.updateChildren(map);
DatabaseReference message_root = root.child(temp_key);
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("uid", user_name);
map2.put("msg", input_msg.getText().toString());
map2.put("likes","0");
map2.put("date",dtSent);
message_root.updateChildren(map2);
input_msg.setText("");
}
});
}
}
What im mainly looking for is how could i access this(Chatrooms/RoomName/UNIQUE_ID/likes) as structured in the database, and update it. Where the Unique id is an actual unique id.
FATAL EXCEPTION: main
Process: com.brunelcs.group13.anyquestions, PID: 8808
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.toString()' on a null object reference
at com.brunelcs.group13.anyquestions.ChatRoom$1.onButtonClick(ChatRoom.java:87)
at com.brunelcs.group13.anyquestions.MessagesListAdapter$1.onClick(MessagesListAdapter.java:81)
at android.view.View.performClick(View.java:6256)
at android.view.View$PerformClick.run(View.java:24697)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Toast toast = Toast.makeText(getApplicationContext(), getPostKey.toString(), Toast.LENGTH_SHORT);
toast.show();
that i put after getPostKey,
and the other one:
if (btnClickListener != null)
btnClickListener.onButtonClick((Integer) view.getTag());}
Also the arrayAdapter had to be changed to this as it was comming up with errors:
final MessagesListAdapter arrayAdapter = new MessagesListAdapter(this, arrayMessages, new MessagesListAdapter.ButtonClickListener() {}
This is how i am posting the data into firebase:
btn_send_msg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String dtSent = ((dateFormat.format(date).toString()));
Map<String, Object> map = new HashMap<String, Object>();
temp_key = root.push().getKey();
// temp key is the randomly generated key
root.updateChildren(map);
DatabaseReference message_root = root.child(temp_key);
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("uid", user_name);
map2.put("msg", input_msg.getText().toString());
map2.put("likes","0");
map2.put("date",dtSent);
message_root.updateChildren(map2);
input_msg.setText("");
}
});
As you can see from answer I posted you in comment you can create an interface inside your Adapter class with one void method and int as parametar for example:
public interface ButtonClickListener {
public abstract void onButtonClick(int position);
}
Then use this in constructor of your adapter class so you can override it inside your Activity and preform ButtonClick. For example:
private ButtonClickListener btnClickListener = null;
public MessagesListAdapter(Context context, ArrayList<MessagesListDataModel> dataModels, ButtonClickListener btnClickListener){
super(context,0, dataModels);
this.dataModels = dataModels;
this.btnClickListener = btnClickListener;
}
After that inside your Adapter class setTag on like button and setOnclickListener on it and get the tag. For example:
likes.setTag(position);
likes.setOnClickListener(new View.OnClickListener{
#Override
public void onClick(View v) {
if(btnClickListener != null)
btnClickListener.onButtonClick((Integer) v.getTag());
}
});
When you are done with this you will be able to implement click listener inside your adapter creation in Activity and then inside using position get the key of post and with that key, retrieve how many likes you have on specific post, make increment and set the value again. Create a new getter and setter inside your model class to store key for example:
private String postKey;
public String getPostKey() {
return postKey;
}
public void setPostKey(String postKey) {
this.postKey = postKey;
}
You will need to store the key inside sePostKey so you can get the key from getPostKey. And then you can easily get it from your MessagesListDataModel:
final MessagesListAdapter arrayAdapter = new MessagesListAdapter(this,arrayMessages, new ButtonClickListener(){
#Override
public void onButtonClick(int position) {
String getPostKey = arrayMessages.get(position).getPostKey();
//Now you have a key to run another query to get data from specific post and with that number of likes as well
}
});
Probably process could be simplified or to use some another better approach but this is just an idea how you could achieve what you want. I didn't test this code I hope it will work.
PostListFragment is extended by other fragments in my app. I need the uid of the current user, but it always returns null. When I try to run my app, I always get the error:
FATAL EXCEPTION: main
Process: com.example.cleeg.squad, PID: 8524
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.google.firebase.auth.FirebaseUser.getUid()' on a null object reference
at com.example.cleeg.squad.fragments.PostListFragment.getUid(PostListFragment.java:162)
at com.example.cleeg.squad.fragments.MyPostsFragment.getQuery(MyPostsFragment.java:19)
at com.example.cleeg.squad.fragments.PostListFragment.onActivityCreated(PostListFragment.java:76)
I've tried to find out why this is online, but I just get more confused and I don't really know how to fix it.
The function getUid() is at the bottom of the code.
public abstract class PostListFragment extends Fragment {
private static final String TAG = "PostListFragment";
private DatabaseReference mDatabaseReference;
private FirebaseRecyclerAdapter<Post, PostViewHolder> mAdapter;
private RecyclerView mRecycler;
private LinearLayoutManager mManager;
public PostListFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_all_posts, container, false);
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
mRecycler = (RecyclerView) rootView.findViewById(R.id.messages_list);
mRecycler.setHasFixedSize(true);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Set up Layout Manager, reverse layout
mManager = new LinearLayoutManager(getActivity());
mManager.setReverseLayout(true);
mManager.setStackFromEnd(true);
mRecycler.setLayoutManager(mManager);
// Set up FirebaseRecyclerAdapter with the Query
Query postsQuery = getQuery(mDatabaseReference);
mAdapter = new FirebaseRecyclerAdapter<Post, PostViewHolder>(Post.class, R.layout.item_post,
PostViewHolder.class, postsQuery) {
#Override
protected void populateViewHolder(final PostViewHolder viewHolder, final Post model, final int position) {
final DatabaseReference postRef = getRef(position);
// Set click listener for the whole post view
final String postKey = postRef.getKey();
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Launch PostDetailActivity
Intent intent = new Intent(getActivity(), PostDetailActivity.class);
intent.putExtra(PostDetailActivity.EXTRA_POST_KEY, postKey);
startActivity(intent);
}
});
// Determine if the current user has liked this post and set UI accordingly
if (model.stars.containsKey(getUid())) {
viewHolder.starView.setImageResource(R.drawable.ic_toggle_star_24);
} else {
viewHolder.starView.setImageResource(R.drawable.ic_toggle_star_outline_24);
}
// Bind Post to ViewHolder, setting OnClickListener for the star button
viewHolder.bindToPost(model, new View.OnClickListener() {
#Override
public void onClick(View starView) {
// Need to write to both places the post is stored
DatabaseReference globalPostRef = mDatabaseReference.child("posts").child(postRef.getKey());
DatabaseReference userPostRef = mDatabaseReference.child("user-posts").child(model.uid).child(postRef.getKey());
// Run two transactions
onStarClicked(globalPostRef);
onStarClicked(userPostRef);
}
});
}
};
mRecycler.setAdapter(mAdapter);
}
private void onStarClicked(DatabaseReference postRef) {
postRef.runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
Post p = mutableData.getValue(Post.class);
if (p == null) {
return Transaction.success(mutableData);
}
if (p.stars.containsKey(getUid())) {
// Unstar the post and remove self from stars
p.starCount = p.starCount - 1;
p.stars.remove(getUid());
} else {
// Star the post and add self to stars
p.starCount = p.starCount + 1;
p.stars.put(getUid(), true);
}
// Set value and report transaction success
mutableData.setValue(p);
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
// Transaction completed
Log.d(TAG, "postTransaction:onComplete:" + databaseError);
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
if (mAdapter != null) {
mAdapter.cleanup();
}
}
public String getUid() {
return FirebaseAuth.getInstance().getCurrentUser().getUid();
}
public abstract Query getQuery(DatabaseReference databaseReference);
}
The crash is because of no user is linked, i.e., getCurrentUser() is null. Please make user you have the user before fetching the userid.
if (FirebaseAuth.getInstance().getCurrentUser() != null) {
mUserID = FirebaseAuth.getInstance().getCurrentUser().getUid();
} else {
//login or register screen
}
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
// User is authenticated and now you can access uesr's properties as followings
mUserID = user.getUid();
} else {
// User is authenticated. So, let's try to re-authenticate
AuthCredential credential = EmailAuthProvider
.getCredential("user#example.com", "password1234");
// Prompt the user to re-provide their sign-in credentials
user.reauthenticate(credential)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Log.d(TAG, "User re-authenticated.");
}
});
}
You can get details on it in this firebase document: https://firebase.google.com/docs/auth/android/manage-users