I'm using a recyclerView that inflates two types of views, to be able to do a chat, everything is fine but it is not sent or received instantly
When I send a message, it is not received unless I click on my edit text,
Which is wrong, because in a chat should show instantly...
My adapter:
public class ChatRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public Context context;
public ArrayList<ChatPersonal> items = new ArrayList<>();
private String mId;
private static final int CHAT_RIGHT = 1;
private static final int CHAT_LEFT = 2;
public ChatRecyclerAdapter (Context context, ArrayList<ChatPersonal> items, String mId){
this.context = context;
this.items = items;
this.mId = mId;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
RecyclerView.ViewHolder holder = null;
switch (viewType){
case CHAT_RIGHT:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_chat_right, parent, false);
holder = new ChatPersonalHolderSender(view);
break;
case CHAT_LEFT:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_chat_left, parent, false);
holder = new ChatPersonalHolder(view);
break;
}
return holder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ChatPersonal mObject = items.get(position);
int itemViewType = getItemViewType(position);
switch(itemViewType){
case CHAT_RIGHT:
((ChatPersonalHolderSender) holder).mMENSAJE.setText(mObject.getMessage());
((ChatPersonalHolderSender) holder).mHORA.setText(DateUtils.getRelativeTimeSpanString(mObject.getHour()));
break;
case CHAT_LEFT:
((ChatPersonalHolder) holder).mMENSAJE.setText(mObject.getMessage());
((ChatPersonalHolder) holder).mHORA.setText(DateUtils.getRelativeTimeSpanString(mObject.getHour()));
break;
}
}
#Override
public int getItemViewType(int position) {
if(items.get(position).getId().equals(mId)){
return CHAT_RIGHT;
}else{
return CHAT_LEFT;
}
}
#Override
public int getItemCount() {
return items.size();
}
}
And this is the relevant code of my chatClass:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
linearLayoutManager = new LinearLayoutManager(ActivityChat.this);
linearLayoutManager.setStackFromEnd(true);
mRecyclerView.setLayoutManager(linearLayoutManager);
mRecyclerView.setHasFixedSize(false);
adapter = new ChatRecyclerAdapter(getApplicationContext(), items, mId);
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
// send message
mSentMensaje.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String message = mEditText.getText().toString();
if (!message.isEmpty()) {
mChat.setMessage(message);
mChat.setHour(System.currentTimeMillis());
mChat.setId(mId);
if(mUser != null){
if(mUser.getIDchat() != null){
FirebaseUtils.getCHATT(mUser.getIDchat()).push().setValue(mChat).addOnSuccessListener(ActivityChat.this, new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
mRecyclerView.scrollToPosition(items.size() -1);
adapter.notifyDataSetChanged();
mEditText.setText("");
}
});
}}
// retreive message
if(mUser != null){
if(mUser.getIDchat() != null){
FirebaseUtils.getCHATT(mUser.getIDchat()).limitToFirst(50).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot != null && dataSnapshot.getValue() != null) {
try{
ChatPersonal model = dataSnapshot.getValue(ChatPersonal.class);
items.add(model);
} catch (Exception ex) {
Log.e(TAG, ex.getMessage());
}
}
}
#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) {
}
});
}
// status
#Override
protected void onStart() {
super.onStart();
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onChanged() {
super.onChanged();
mRecyclerView.scrollToPosition(adapter.getItemCount() - 1);
}
});
}
#Override
protected void onResume() {
super.onResume();
adapter.notifyDataSetChanged();
}
#Override
protected void onPostResume() {
super.onPostResume();
adapter.notifyDataSetChanged();
}
}
If you want the data to be synced with Firebase automatically, you need to use FirebaseRecyclerAdapter
Reference: https://github.com/firebase/FirebaseUI-Android/blob/master/database/src/main/java/com/firebase/ui/database/FirebaseRecyclerAdapter.java
Related
I'm making a chat app. I have a recycler view. I use Picasso to download the images of the user and the friend he is chatting with. To not download the image for every message, when I download the first image I just put it into a bitmap and use it every time.
PROBLEM: I can't call NotifyDataSetChanged. I have tried every possible thing I've found on the net.
ERROR :
Cannot call this method while RecyclerView is computing a layout or scrolling android.support.v7.widget.RecyclerView
I have to "manually" refresh the view so that the images are loaded. No problem for the text.
It runs with the Handler but it doesn't even go in the function (so the view isn't refreshed).
Here is my code (everything works except this notifydatasetchanged)
public class ChatActivity extends AppCompatActivity {
private RecyclerView recyclerChat;
private ListMessageAdapter adapter;
private EditText editWriteMessage;
private LinearLayoutManager linearLayoutManager;
private FirebaseAuth mAuth;
private DatabaseReference UserRef, MessageIDREF, UserMessageRef, SendMessageUser;
private List<ChatClass> ListOfChats = new ArrayList<>();
private ImageButton btnSend;
private String currentUserID, currentDateMessage, currentTimeMessage;
private CommunActivit obj = new CommunActivit();
private String FRIENDID;
private Toolbar mToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
mAuth=FirebaseAuth.getInstance();
currentUserID = mAuth.getCurrentUser().getUid();
MessageIDREF = FirebaseDatabase.getInstance().getReference().child("Friends");
UserMessageRef = FirebaseDatabase.getInstance().getReference().child("Message").child(obj.getsIDMESSAGE());
btnSend = (ImageButton) findViewById(R.id.btnSend);
editWriteMessage = (EditText) findViewById(R.id.editWriteMessage) ;
FRIENDID = obj.getsIDFRIEND();
mToolbar = (Toolbar) findViewById(R.id.main_app_bar2);
setSupportActionBar(mToolbar);
ActionBar ab = getSupportActionBar();
final String Title = obj.getsFRIENDName();
ab.setTitle(Title);
btnSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SendMessageToGroupChat();
editWriteMessage.setText("");
}
});
retrievedata();
/*recyclerChat = (RecyclerView)findViewById(R.id.recyclerChat);
adapter = new ListMessageAdapter(this,ListOfChats);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerChat.setLayoutManager(layoutManager);
recyclerChat.setItemAnimator(new DefaultItemAnimator());
recyclerChat.setAdapter(adapter);*/
linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerChat = (RecyclerView) findViewById(R.id.recyclerChat);
recyclerChat.setLayoutManager(linearLayoutManager);
adapter = new ListMessageAdapter(this, ListOfChats);
recyclerChat.setAdapter(adapter);
/* editWriteMessage.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
recyclerChat.smoothScrollToPosition(adapter.getItemCount());
return false;
}
});*/
}
private void SendMessageToGroupChat() {
String message = editWriteMessage.getText().toString();
String messageKey = UserMessageRef.push().getKey();
if (TextUtils.isEmpty(message)) {
Toast.makeText(this, "Please write a message first", Toast.LENGTH_SHORT).show();
} else {
Calendar calendarDate = Calendar.getInstance();
SimpleDateFormat DateFormat = new SimpleDateFormat("MMM dd, yyyy");
currentDateMessage = DateFormat.format(calendarDate.getTime());
Calendar calendarTime = Calendar.getInstance();
SimpleDateFormat TimeFormat = new SimpleDateFormat("hh:mm a");
currentTimeMessage = TimeFormat.format(calendarTime.getTime());
HashMap<String, Object> groupMessageKey = new HashMap<>();
UserMessageRef.updateChildren(groupMessageKey);
SendMessageUser = UserMessageRef.child(messageKey);
HashMap<String, Object> messageInfoMap = new HashMap<>();
messageInfoMap.put("name", obj.getsUsername());
messageInfoMap.put("message", message);
messageInfoMap.put("date", currentDateMessage);
messageInfoMap.put("time", currentTimeMessage);
messageInfoMap.put("image", obj.getsUserImageLink());
SendMessageUser.updateChildren(messageInfoMap);
}
}
public void retrievedata() {
UserMessageRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) /**** HERE IS THE PROBLEM***/
{
if (dataSnapshot.exists()) {
DisplayMessages(dataSnapshot);
}
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
if (dataSnapshot.exists()) {
DisplayMessages(dataSnapshot);
}
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private void DisplayMessages(DataSnapshot dataSnapshot)
{
Iterator iterator = dataSnapshot.getChildren().iterator();
while (iterator.hasNext()) {
String chatDate = (String) ((DataSnapshot) iterator.next()).getValue();
String chatImage = (String) ((DataSnapshot) iterator.next()).getValue();
String chatMessage = (String) ((DataSnapshot) iterator.next()).getValue();
String chatName = (String) ((DataSnapshot) iterator.next()).getValue();
String chatTime = (String) ((DataSnapshot) iterator.next()).getValue();
ListOfChats.add(new ChatClass(chatName, chatMessage, chatDate + " " + chatTime, chatImage));
adapter.notifyDataSetChanged();
recyclerChat.smoothScrollToPosition(adapter.getItemCount()); /**AUTO SCROLL**/
}
}
class ListMessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private ChatClass consersation;
private List<ChatClass> List_of_chats;
private CommunActivit obj = new CommunActivit();
private Bitmap BitmapUser;
private Bitmap BitmapFriend;
public ListMessageAdapter(Context context, List<ChatClass> List_of_chats) {
this.context = context;
this.List_of_chats = List_of_chats;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == 1) {
View view = LayoutInflater.from(context).inflate(R.layout.rc_item_message_friend, parent, false);
return new ItemMessageFriendHolder(view);
} else if (viewType == 2) {
View view = LayoutInflater.from(context).inflate(R.layout.rc_item_message_user, parent, false);
return new ItemMessageUserHolder(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final int pos =position;
if (holder instanceof ItemMessageFriendHolder) {
((ItemMessageFriendHolder) holder).txtContent.setText(List_of_chats.get(position).getMessage());
if (BitmapFriend == null) {
Picasso.get().load(List_of_chats.get(position).getImageLink()).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
BitmapFriend = bitmap;
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
((ItemMessageFriendHolder) holder).avata.setImageBitmap(BitmapFriend);
}
else
{
((ItemMessageFriendHolder) holder).avata.setImageBitmap(BitmapFriend);
new Handler().post(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
});
}
}
else
{
if (holder instanceof ItemMessageUserHolder) {
((ItemMessageUserHolder) holder).txtContent.setText(List_of_chats.get(position).getMessage());
if (BitmapUser == null) {
Picasso.get().load(List_of_chats.get(position).getImageLink()).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
BitmapUser = bitmap;
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
((ItemMessageUserHolder) holder).avata.setImageBitmap(BitmapUser);
} else {
((ItemMessageUserHolder) holder).avata.setImageBitmap(BitmapUser);
new Handler().post(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
});
}
}
}
}
#Override
public int getItemViewType(int position) {
int viewtype = -1;
if (List_of_chats.get(position).getUsername().equals(obj.getsUsername())) {
return 2;
}
else
{
return 1;
}
}
#Override
public int getItemCount() {
return List_of_chats.size();
}
}
class ItemMessageUserHolder extends RecyclerView.ViewHolder {
public TextView txtContent;
public CircleImageView avata;
public ItemMessageUserHolder(View itemView) {
super(itemView);
txtContent = (TextView) itemView.findViewById(R.id.textContentUser);
avata = (CircleImageView) itemView.findViewById(R.id.imageView2);
}
}
class ItemMessageFriendHolder extends RecyclerView.ViewHolder {
public TextView txtContent;
public CircleImageView avata;
public ItemMessageFriendHolder(View itemView) {
super(itemView);
txtContent = (TextView) itemView.findViewById(R.id.textContentFriend);
avata = (CircleImageView) itemView.findViewById(R.id.imageView3);
}
}
It is because you're calling notifyDataSetChanged inside your onBindViewHolder like this:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
...
((ItemMessageFriendHolder) holder).avata.setImageBitmap(BitmapFriend);
new Handler().post(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
});
...
}
You shouldn't force the Adapter to refresh itself before it isn't finished binding the view yet.
So, you need to remove the following code from your onBindViewHolder:
new Handler().post(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
});
then just call notifyDataSetChanged() when you need it. For example, when your dataset is changed.
Try this.
dialeecyclerView.post(new Runnable()
{
#Override
public void run() {
myadapter.notifyDataSetChanged();
}
});
Source - Cannot call this method while RecyclerView is computing a layout or scrolling when try remove item from recyclerview
My app cannot get the right position to perform the task that user choose from ContextMenu.
MainActivity.java
public class Main3Activity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<foodmodel> result;
private foodadapter adapter;
private FirebaseDatabase database;
private DatabaseReference ref;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
database = FirebaseDatabase.getInstance();
ref = database.getReference("Food");
result = new ArrayList<>();
recyclerView = (RecyclerView)findViewById(R.id.food_list);
recyclerView.setHasFixedSize(true);
LinearLayoutManager lim = new LinearLayoutManager(this);
lim.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(lim);
adapter = new foodadapter(result);
recyclerView.setAdapter(adapter);
updateList();
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId())
{
case 0:
removeFood(item.getItemId());
break;
case 1:
changeFood(item.getItemId());
break;
}
return super.onContextItemSelected(item);
}
private void updateList()
{
ref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
result.add(dataSnapshot.getValue(foodmodel.class));
adapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
foodmodel food = dataSnapshot.getValue(foodmodel.class);
int index = getItemIndex(food);
result.set(index,food);
adapter.notifyItemChanged(index);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
foodmodel food = dataSnapshot.getValue(foodmodel.class);
int index = getItemIndex(food);
result.remove(index);
adapter.notifyItemRemoved(index);
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private int getItemIndex(foodmodel food){
int index = -1;
for(int i = 0; i < result.size();i++)
{
if (result.get(i).key.equals(food.key))
{
index = i;
break;
}
}
return index;
}
private void removeFood(int pos){
foodmodel food = result.get(pos);
String key = food.getKey();
food.u_time="remove";
Map<String,Object> foodValue = food.toMap();
Map<String,Object> newFood = new HashMap<>();
newFood.put(key,foodValue);
ref.updateChildren(newFood);
}
private void changeFood(int pos){
foodmodel food = result.get(pos);
food.u_time="change";
Map<String,Object> foodValue = food.toMap();
Map<String,Object> newFood = new HashMap<>();
newFood.put(food.key,foodValue);
ref.updateChildren(newFood);
}
}
foodadapter.java
public class foodadapter extends RecyclerView.Adapter<foodadapter.foodviewholder> {
private List<foodmodel>list;
public foodadapter(List<foodmodel> list) {
this.list = list;
}
#Override
public foodviewholder onCreateViewHolder(ViewGroup parent, int viewType) {
return new foodviewholder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_item,parent,false));
}
#Override
public void onBindViewHolder(foodviewholder holder, int position) {
foodmodel food = list.get(position);
holder.txtname.setText(food.u_food);
holder.txtdate.setText(food.u_date);
holder.txttime.setText(food.u_time);
}
#Override
public int getItemCount() {
return list.size();
}
public class foodviewholder extends RecyclerView.ViewHolder implements OnCreateContextMenuListener {
TextView txtname,txtdate,txttime;
Button btn;
public foodviewholder(View itemView) {
super(itemView);
txtname = (TextView)itemView.findViewById(R.id.text_food);
txtdate = (TextView)itemView.findViewById(R.id.text_date);
txttime = (TextView)itemView.findViewById(R.id.text_time);
btn = (Button)itemView.findViewById(R.id.btntest);
itemView.setOnCreateContextMenuListener(this);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.add(0, 0, 0, "Delete");
menu.add(0, 1, 0, "Change");
}
}
}
foomodel.java
public class foodmodel {
String u_food,u_date,u_time,key;
public foodmodel(){}
public foodmodel(String u_food,String u_date,String u_time, String key) {
this.u_food = u_food;
this.u_date = u_date;
this.u_time = u_time;
this.key = key;
}
public Map<String,Object> toMap(){
HashMap<String,Object> result = new HashMap<>();
result.put("u_food",u_food);
result.put("u_time",u_time);
result.put("u_date",u_date);
result.put("key",key);
return result;
}
public String getU_food() {
return u_food;
}
public void setU_food(String u_food) {
this.u_food = u_food;
}
public String getU_date() {
return u_date;
}
public void setU_date(String u_date) {
this.u_date = u_date;
}
public String getU_time() {
return u_time;
}
public void setU_time(String u_time) {
this.u_time = u_time;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
The flow of the app supposed like
display recyclerview that retrieve from Firebases
user choose the item from the list
contextmenu pop up
user choose delete or change
if delete, then the u_time of food becomes "remove"
if change, then the u_time of food becomes "change"
the step from 1-4 works fine. but after that the app cannot get position to perform task correctly.
For example, if user choose "delete" on third item, but the first item will be changed. After that, user choose "change" on forth item, the second item changed. Is there any problem of my code?
Replace your code like :
MainActivity.java
public class Main3Activity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<foodmodel> result;
private foodadapter adapter;
private FirebaseDatabase database;
private DatabaseReference ref;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
database = FirebaseDatabase.getInstance();
ref = database.getReference("Food");
result = new ArrayList<>();
recyclerView = (RecyclerView)findViewById(R.id.food_list);
recyclerView.setHasFixedSize(true);
LinearLayoutManager lim = new LinearLayoutManager(this);
lim.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(lim);
adapter = new foodadapter(result);
recyclerView.setAdapter(adapter);
updateList();
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId())
{
case 0:
if(adapter.curPos>-1){
removeFood(adapter.curPos);
}
break;
case 1:
if(adapter.curPos>-1){
changeFood(adapter.curPos);
}
break;
}
return super.onContextItemSelected(item);
}
private void updateList()
{
ref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
result.add(dataSnapshot.getValue(foodmodel.class));
adapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
foodmodel food = dataSnapshot.getValue(foodmodel.class);
int index = getItemIndex(food);
result.set(index,food);
adapter.notifyItemChanged(index);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
foodmodel food = dataSnapshot.getValue(foodmodel.class);
int index = getItemIndex(food);
result.remove(index);
adapter.notifyItemRemoved(index);
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private int getItemIndex(foodmodel food){
int index = -1;
for(int i = 0; i < result.size();i++)
{
if (result.get(i).key.equals(food.key))
{
index = i;
break;
}
}
return index;
}
private void removeFood(int pos){
foodmodel food = result.get(pos);
String key = food.getKey();
food.u_time="remove";
Map<String,Object> foodValue = food.toMap();
Map<String,Object> newFood = new HashMap<>();
newFood.put(key,foodValue);
ref.updateChildren(newFood);
}
private void changeFood(int pos){
foodmodel food = result.get(pos);
food.u_time="change";
Map<String,Object> foodValue = food.toMap();
Map<String,Object> newFood = new HashMap<>();
newFood.put(food.key,foodValue);
ref.updateChildren(newFood);
}
}
foodadapter.java
public class foodadapter extends RecyclerView.Adapter<foodadapter.foodviewholder> {
private List<foodmodel>list;
public int curPos=-1;
public foodadapter(List<foodmodel> list) {
this.list = list;
}
#Override
public foodviewholder onCreateViewHolder(ViewGroup parent, int viewType) {
return new foodviewholder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_item,parent,false));
}
#Override
public void onBindViewHolder(foodviewholder holder, int position) {
foodmodel food = list.get(position);
holder.txtname.setText(food.u_food);
holder.txtdate.setText(food.u_date);
holder.txttime.setText(food.u_time);
}
#Override
public int getItemCount() {
return list.size();
}
public class foodviewholder extends RecyclerView.ViewHolder implements OnCreateContextMenuListener {
TextView txtname,txtdate,txttime;
Button btn;
public foodviewholder(View itemView) {
super(itemView);
txtname = (TextView)itemView.findViewById(R.id.text_food);
txtdate = (TextView)itemView.findViewById(R.id.text_date);
txttime = (TextView)itemView.findViewById(R.id.text_time);
btn = (Button)itemView.findViewById(R.id.btntest);
itemView.setOnCreateContextMenuListener(this);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
curPos=getAdapterPosition();
}});
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.add(0, 0, 0, "Delete");
menu.add(0, 1, 0, "Change");
}
}
}
I have an adapter class where I am able to load all video from Firebase. But the problem is I can't load both, image and video in one RecyclerView
See what I have done:
I am using toro library to auto play video if your wondering and ExoPlayer to play video
This is my adapter class
public class MainFeedAdapter extends RecyclerView.Adapter<TestAdapter.MyViewHolder> {
private static final String TAG = "MainfeedAdapter";
private List<Photo> moviesList;
private DatabaseReference mReference;
private Context mContext;
private String currentUsername = "";
private int mLayoutResource;
private LayoutInflater mInflater;
private Photo photo;
private MyViewHolder mHolder;
public class MyViewHolder extends RecyclerView.ViewHolder implements ToroPlayer{
static final int LAYOUT_RES = R.layout.main_list;
private ExoPlayerViewHelper helper;
private CircleImageView profile_image;
//private String likeString;
private TextView username,time,caption,likes,comment,stars;
private SquareImageView image;
private LikeButton mHeart,Star;
private UserAccountSettings userAccountSettings = new UserAccountSettings();
private User user = new User();
private StringBuilder users;
private String mLIkeString;
private String mStarString;
private boolean likeByCurrentUSer;
private boolean starbycurrentuser;
private DatabaseReference mNotification;
private ImageView commentBubble;
private Uri mediaUri;
#BindView(R.id.main_post_image2)
PlayerView playerView;
private CardView video;
public MyViewHolder(View view) {
super(view);
profile_image = (CircleImageView)view.findViewById(R.id.post_profile_photo);
username = (TextView) view.findViewById(R.id.main_username);
time = (TextView) view.findViewById(R.id.main_image_time_posted);
caption = (TextView) view.findViewById(R.id.main_image_caption);
likes = (TextView) view.findViewById(R.id.main_likes);
comment = (TextView) view.findViewById(R.id.main_showcomments);
image = (SquareImageView) view.findViewById(R.id.main_post_image);
mHeart = (LikeButton) view.findViewById(R.id.main_heart);
Star = (LikeButton) view.findViewById(R.id.main_star);
stars= (TextView)view.findViewById(R.id.stars);
commentBubble = (ImageView)view.findViewById(R.id.main_comments) ;
mNotification = FirebaseDatabase.getInstance().getReference().child("notification");
mReference = FirebaseDatabase.getInstance().getReference();
ButterKnife.bind(this, itemView);
video = (CardView)view.findViewById(R.id.video_posts);
}
#NonNull
#Override
public View getPlayerView() {
return playerView;
}
#NonNull
#Override
public PlaybackInfo getCurrentPlaybackInfo() {
return helper != null ? helper.getLatestPlaybackInfo() : new PlaybackInfo();
}
#Override
public void initialize(#NonNull Container container, #Nullable PlaybackInfo playbackInfo) {
if (helper == null) {
helper = new SimpleExoPlayerViewHelper(container, this, mediaUri);
}
helper.initialize(playbackInfo);
}
// called from Adapter to setup the media
void bind( Uri item, List<Photo> payloads) {
if (item != null) {
mediaUri = item;
}else {
video.setVisibility(View.GONE);
}
}
#Override
public void play() {
if (helper != null) helper.play();
}
#Override
public void pause() {
if (helper != null) helper.pause();
}
#Override
public boolean isPlaying() {
return helper != null && helper.isPlaying();
}
#Override
public void release() {
if (helper != null) {
helper.release();
helper = null;
}
}
#Override
public boolean wantsToPlay() {
return ToroUtil.visibleAreaOffset(this, itemView.getParent()) >= 0.85;
}
#Override
public int getPlayerOrder() {
return getAdapterPosition();
}
#Override
public void onSettled(Container container) {
}
}
public TestAdapter(List<Photo> moviesList) {
this.moviesList = moviesList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.main_list, parent, false);
mContext = parent.getContext();
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
photo = moviesList.get(position);
mHolder = holder;
holder.users = new StringBuilder();
getCurrentUsername();
getLikesString(mHolder);
getStarString(mHolder);
holder.bind(Uri.parse(photo.getVideo_path()),moviesList);
//get the profile image and username
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference
.child(mContext.getString(R.string.dbname_user_account_settings))
.orderByChild(mContext.getString(R.string.field_user_id))
.equalTo(getItem(position).getUser_id());
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
// currentUsername = singleSnapshot.getValue(UserAccountSettings.class).getUsername();
Log.d(TAG, "onDataChange: found user: "
+ singleSnapshot.getValue(UserAccountSettings.class).getUsername());
holder.username.setText(singleSnapshot.getValue(UserAccountSettings.class).getUsername());
holder.username.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: navigating to profile of: " +
holder.user.getUsername());
Intent intent = new Intent(mContext, Profile_Activity.class);
intent.putExtra(mContext.getString(R.string.calling_activity),
mContext.getString(R.string.home_activity));
intent.putExtra(mContext.getString(R.string.intent_user), holder.user);
mContext.startActivity(intent);
}
});
imageLoader.displayImage(singleSnapshot.getValue(UserAccountSettings.class).getProfile_photo(),
holder.profile_image);
holder.profile_image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: navigating to profile of: " +
holder.user.getUsername());
Intent intent = new Intent(mContext, Profile_Activity.class);
intent.putExtra(mContext.getString(R.string.calling_activity),
mContext.getString(R.string.home_activity));
intent.putExtra(mContext.getString(R.string.intent_user), holder.user);
mContext.startActivity(intent);
}
});
holder.userAccountSettings = singleSnapshot.getValue(UserAccountSettings.class);
holder.comment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((HomeActivity)mContext).onCommentThreadSelected(getItem(position),mContext.getString(R.string.home_activity));
//another thing?
((HomeActivity)mContext).hideLayout();
}
});
holder.commentBubble.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((HomeActivity)mContext).onCommentThreadSelected(getItem(position),mContext.getString(R.string.home_activity));
//another thing?
((HomeActivity)mContext).hideLayout();
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Query userQuery = mReference
.child(mContext.getString(R.string.dbname_users))
.orderByChild(mContext.getString(R.string.field_user_id))
.equalTo(getItem(position).getUser_id());
userQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
Log.d(TAG, "onDataChange: found user: " +
singleSnapshot.getValue(User.class).getUsername());
holder.user = singleSnapshot.getValue(User.class);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private boolean rechedendoflist(int position){
return position == getItemCount() -1;\
}
#Override
public int getItemCount() {
return moviesList.size();
}
public Photo getItem(int position) {
return moviesList.get(position);
}
private void getCurrentUsername(){
Log.d(TAG, "getCurrentUser: ");
Log.d(TAG, "getCurrentUsername: retrieving user account settings");
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference
.child(mContext.getString(R.string.dbname_users))
.orderByChild(mContext.getString(R.string.field_user_id))
.equalTo(FirebaseAuth.getInstance().getCurrentUser().getUid());
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
currentUsername = singleSnapshot.getValue(UserAccountSettings.class).getUsername();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Please help me guys!. Thanks in Advance!.
TheRecyclerView has ability to show items in multiple types.
In your case you can define two ViewType. one for Images and another for Videos.
Search about RecyclerView with multiple view types.
Take a look at here and this.
Also here is a question and answers about it.
Tried answers found on the internet, actually there is no change to the code as it seem correct but can't find where is the error.
My Input Parameters:
JSON RETURNED:
(I expected a "clocation" child and value but it won't even write that to the tree. Plus, the value of clocation is written to cbudget)
Project Class:
public class Project {
String ctitle, cdetail, clocation, cbudget;
public Project() {
}
public String getCtitle() {
return ctitle;
}
public void setCtitle(String ctitle) {
this.ctitle = ctitle;
}
public String getCdetail() {
return cdetail;
}
public void setCdetail(String cdetail) {
this.cdetail = cdetail;
}
public String getClocation() {
return clocation;
}
public void setClocation(String clocation) {
this.clocation = clocation;
}
public String getCbudget() {
return cbudget;
}
public void setCbudget(String cbudget) {
this.cbudget = cbudget;
}
MyViewHolder
public MyViewHolder(View itemView) {
super(itemView);
titleTxt = (TextView) itemView.findViewById(R.id.titleTxt);
detailTxt = (TextView) itemView.findViewById(R.id.detailTxt);
locationTxt = (TextView) itemView.findViewById(R.id.locationTxt);
budgetTxt = (TextView) itemView.findViewById(R.id.budgetTxt);
itemView.setOnClickListener(this);
}
MyAdapter
public MyAdapter(Context c, ArrayList<Project> projects) {
this.c = c;
this.projects = projects;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(c).inflate(R.layout.model,parent,false);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final Project s = projects.get(position);
holder.titleTxt.setText(s.getCtitle());
holder.detailTxt.setText(s.getCdetail());
holder.locationTxt.setText(s.getClocation());
holder.budgetTxt.setText(s.getCbudget());
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onItemClick(int pos) {
//OPEN DETAIL ACTIVITY
openDetailActivity(s.getCtitle(),s.getCdetail(),s.getClocation(),s.getCbudget());
}
});
}
#Override
public int getItemCount() {
return projects.size();
}
//OPEN DETAIL ACTIVITY
private void openDetailActivity(String...details)
{
Intent i=new Intent(c,DetailActivity.class);
i.putExtra("TITLE_KEY",details[0]);
i.putExtra("DETAIL_KEY",details[1]);
i.putExtra("LOCATION_KEY",details[2]);
i.putExtra("BUDGET_KEY",details[3]);
c.startActivity(i);
}
FirebaseHelper
public class FirebaseHelper {
DatabaseReference db;
Boolean saved = null;
ArrayList<Project> projects=new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//WRITE IF NOT NULL
public Boolean save(Project project)
{
if(project==null)
{
saved=false;
}
else
{
try
{
db.child("Project").push().setValue(project);
saved=true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved=false;
}
}
return saved;
}
//IMPLEMENT FETCH DATA AND FILL ARRAYLIST
private void fetchData(DataSnapshot dataSnapshot)
{
projects.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Project project = ds.getValue(Project.class);
projects.add(project);
}
}
//READ THEN RETURN ARRAYLIST
public ArrayList<Project> retrieve() {
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return projects;
}
}
Receive and Bind Data:
//RECEIVE DATA
String title = i.getExtras().getString("TITLE_KEY");
String detail = i.getExtras().getString("DETAIL_KEY");
String location = i.getExtras().getString("LOCATION_KEY");
String budget = i.getExtras().getString("BUDGET_KEY");
//BIND DATA
titleTxt.setText(title);
detailTxt.setText(detail);
locationTxt.setText(location);
budgetTxt.setText(budget);
The problem in your code is that you are declaring the ArrayList<Project> projects=new ArrayList<>(); outside onChildAdded() and onChildChanged() methods. This means that your projects ArrayList is null, due the asyncronious behaviour of those methods, which are called before even you add those objects to the list.
To solve this, you need to declare that ArrayList inside fetchData() method right before that for loop.
This change will solve your problem.
1- MainActivity:
public class MainActivity extends AppCompatActivity {
private List<String> mListItems = Arrays.asList("Hamaki","Amr Diab");
private ArtistsAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView)findViewById(R.id.Artist_list_view);
mAdapter = new ArtistsAdapter(this, mListItems);
listView.setAdapter(mAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(MainActivity.this,SoundActivity.class);
intent.putExtra("Artist", mListItems.get(position));
startActivity(intent);
}
});
}
}
2-Sound Activity:
public class SoundActivity extends AppCompatActivity {
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sound);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(R.id.container, new SoundFragment()).commit();
}
}
3-Sound Fragment:
public class SoundFragment extends Fragment {
static SCTrackAdapter mAdapter;
static DatabaseReference db;
static FirebaseHelper helper;
private TextView mSelectedTrackTitle;
static ArrayList<Music> mTracks = new ArrayList<>();
static MediaPlayer mMediaPlayer;
private ImageView mPlayerControl;
static String Artist;
static ListView listView;
int currentTrack;
private static String fileName;
public SoundFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onStart() {
super.onStart();
new Fetchtracks().execute();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_sound, container, false);
Intent intent = getActivity().getIntent();
if (intent != null) {
Artist = intent.getStringExtra("Artist");
}
listView = (ListView) rootView.findViewById(R.id.track_list_view);
mAdapter = new SCTrackAdapter(getActivity(), mTracks);
listView.setAdapter(mAdapter);
return rootView;
}
4- STrack Adapter:
public class SCTrackAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<Music> mTracks;
public SCTrackAdapter(Context context, ArrayList<Music> tracks) {
mContext = context;
mTracks = tracks;
}
public void update_tracks(ArrayList<Music> list)
{
mTracks.clear();
mTracks.addAll(list);
}
#Override
public int getCount() {
return mTracks.size();
}
#Override
public Music getItem(int position) {
return mTracks.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.track_list_row, parent, false);
holder = new ViewHolder();
holder.titleTextView = (TextView) convertView.findViewById(R.id.track_title);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.titleTextView.setText(mTracks.get(position).getName());
return convertView;
}
static class ViewHolder {
TextView titleTextView;
}
}
5- Fetchtracks:
public class Fetchtracks extends AsyncTask<Void, Void, ArrayList<Music>> {
#Override
protected ArrayList<Music> doInBackground(Void... voids) {
db = FirebaseDatabase.getInstance().getReference().child(Artist);
helper = new FirebaseHelper(db);
mTracks.addAll(helper.retrieve());
Log.e("doInBackground: ",helper.retrieve()+"");
return mTracks;
}
#Override
protected void onPostExecute(ArrayList<Music> list) {
super.onPostExecute(list);
Log.e("doInBackground: ",list.size()+"");
mAdapter.update_tracks(list);
mAdapter.notifyDataSetChanged();
}
}
6- FirebaseHelper:
public class FirebaseHelper {
DatabaseReference db;
Boolean saved=null;
ArrayList<Music> A = new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//WRITE
public Boolean save(Music m)
{
if(m==null)
{
saved=false;
}else
{
try
{
// db.child(Artist).push().setValue(m);
saved=true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved=false;
}
}
return saved;
}
//READ
public ArrayList<Music> retrieve()
{
A.clear();
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.e("onChildAdded: ", "1");
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Log.e("onChildAdded: ", "2");
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
// Log.e("onChildAdded: ", "3");
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
// Log.e("onChildAdded: ", "4");
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Log.e("onChildAdded: ", "5");
}
});
return A;
}
private void fetchData(DataSnapshot dataSnapshot)
{
Music m=new Music();
m.setName(dataSnapshot.child("name").getValue().toString());
m.setUrl(dataSnapshot.child("url").getValue().toString());
A.add(m);
// SoundFragment.mTracks.add(m);
// Log.e("onFetch: ", SoundFragment.mTracks.size()+"");
}
}
7- Music:
public class Music {
String name;
String url;
public Music() {
}
public void setName(String name) {
this.name = name;
}
public void setUrl(String url) {
this.url = url;
}
public String getName() {
return name;
}
public String getURL() {
return url;
}
}
no need to call this in onPostExecute() as it is only set
listView.setAdapter(mAdapter);