I am currently working on a WhatsApp-like Android application and I recently ran into a problem which gave me a headache. I am trying to create a RecyclerView inside a Fragment belonging to a TabLayout. Basically, I have 3 tabs, each containing a Fragment. The first Tab is for the user's conversations, the second one is for the groups and the third is for the contacts. Each tab should contain a RecyclerView which displays data from the Firebase Firestore according to the current user's ID provided by the Firebase Authentication. The problem I think is coming from the fact that inside the Fragment besides the RecyclerView I also have a FloatingActionButton. This button is used in each Fragment for performing actions like sending a new message or creating a new group or adding a new contact. When clicked, let's say inside the groups tab, the FAB displays an AlertDialog asking the user to complete the group name and then select "Create" and the group is created and added into the database. Now, the problem is that when the user logs into the app and accesses the groups tab, his groups are not displayed, but if the user clicks on the FAB, the AlertDialog appears and if the user clicks the EditText in order to pick a name for a new group, suddenly the user's groups are displayed inside the Fragment. I need some help with this, I don't have much experience with Android and I think I am messing up the layouts, but I can't really figure it out by myself.
Here is my code:
MainActivity.java
package com.example.snakemessenger;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import android.view.MenuItem;
import com.google.android.material.tabs.TabLayout;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.viewpager.widget.ViewPager;
import android.view.Menu;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "SnakeMessenger";
private FirebaseAuth mAuth;
private FirebaseFirestore db;
private StorageReference storageReference;
private ViewPager mViewPager;
private TabLayout mTabLayout;
private TabsAccessorAdapter mTabsAccessorAdapter;
private FirebaseUser currentUser;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar mToolbar = findViewById(R.id.main_page_toolbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setTitle("Snake Messenger");
mAuth = FirebaseAuth.getInstance();
db = FirebaseFirestore.getInstance();
storageReference = FirebaseStorage.getInstance().getReference();
currentUser = mAuth.getCurrentUser();
if (currentUser == null) {
sendUserToLoginActivity();
}
mViewPager = findViewById(R.id.main_tabs_pager);
mTabsAccessorAdapter = new TabsAccessorAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mTabsAccessorAdapter);
mTabLayout = findViewById(R.id.main_tabs);
mTabLayout.setupWithViewPager(mViewPager);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.options_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
super.onOptionsItemSelected(item);
if (item.getItemId() == R.id.main_find_friends_option) {
// TODO
} else if (item.getItemId() == R.id.main_settings_option) {
sendUserToSettingsActivity();
} else if (item.getItemId() == R.id.main_sign_out_option) {
mAuth.signOut();
sendUserToLoginActivity();
Toast.makeText(MainActivity.this, "Signed out", Toast.LENGTH_SHORT).show();
}
return true;
}
private void sendUserToSettingsActivity() {
Intent settingsIntent = new Intent(MainActivity.this, SettingsActivity.class);
startActivity(settingsIntent);
}
private void sendUserToLoginActivity() {
Intent loginIntent = new Intent(MainActivity.this, SignInActivity.class);
loginIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(loginIntent);
finish();
}
}
TabsAccessorAdapter.java
package com.example.snakemessenger;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
public class TabsAccessorAdapter extends FragmentPagerAdapter {
public TabsAccessorAdapter(@NonNull FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ChatsFragment();
case 1:
return new GroupsFragment();
case 2:
return new FriendsFragment();
default:
return null;
}
}
@Override
public int getCount() {
return 3;
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Chats";
case 1:
return "Groups";
case 2:
return "Friends";
default:
return null;
}
}
}
GroupsFragment.java
package com.example.snakemessenger;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.firebase.firestore.QuerySnapshot;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.hdodenhof.circleimageview.CircleImageView;
/**
* A simple {@link Fragment} subclass.
*/
public class GroupsFragment extends Fragment {
private View groupFragmentView;
private RecyclerView mGroupsRecyclerView;
private List<Group> groups;
private FloatingActionButton mCreateGroup;
private FirebaseAuth mAuth;
private FirebaseUser currentUser;
private FirebaseFirestore db;
public GroupsFragment() {
// Required empty public constructor
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAuth = FirebaseAuth.getInstance();
currentUser = mAuth.getCurrentUser();
db = FirebaseFirestore.getInstance();
groups = new ArrayList<>();
db.collection("users")
.document(currentUser.getUid())
.collection("groups")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
groups.add(document.toObject(Group.class));
}
Toast.makeText(getActivity(), "Groups received successfully", Toast.LENGTH_SHORT).show();
} else {
Log.d(MainActivity.TAG, "Error getting document: ", task.getException());
Toast.makeText(getContext(), "Failed getting groups", Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
groupFragmentView = inflater.inflate(R.layout.fragment_groups, container, false);
mCreateGroup = groupFragmentView.findViewById(R.id.create_group_btn);
mCreateGroup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
requestNewGroup();
}
});
initView();
setLayoutManager();
setAdapter();
return groupFragmentView;
}
private void initView() {
mGroupsRecyclerView = groupFragmentView.findViewById(R.id.groups_recycler_view);
}
private void setLayoutManager() {
RecyclerView.LayoutManager layoutManager =
new LinearLayoutManager(getActivity());
mGroupsRecyclerView.setLayoutManager(layoutManager);
}
private void setAdapter() {
GroupsAdapter groupsAdapter = new GroupsAdapter(getContext(), groups);
mGroupsRecyclerView.setAdapter(groupsAdapter);
}
private void requestNewGroup() {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AlertDialog);
builder.setTitle("Enter group name");
final LinearLayout layout = new LinearLayout(groupFragmentView.getContext());
layout.setOrientation(LinearLayout.VERTICAL);
final CircleImageView mGroupImage = new CircleImageView(groupFragmentView.getContext());
mGroupImage.setId(R.id.set_group_image);
mGroupImage.setImageResource(R.drawable.group_image);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(200, 200);
layout.addView(mGroupImage);
final EditText mGroupName = new EditText(groupFragmentView.getContext());
mGroupName.setId(R.id.set_group_name);
mGroupName.setGravity(Gravity.CENTER);
mGroupName.setHint("Group name");
layout.addView(mGroupName);
builder.setView(layout);
builder.setPositiveButton("Create", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
EditText mGroupName = layout.findViewById(R.id.set_group_name);
String groupName = mGroupName.getText().toString();
if (TextUtils.isEmpty(groupName)) {
Toast.makeText(getActivity(), "Please write the name of the group", Toast.LENGTH_SHORT).show();
} else {
createNewGroup(groupName);
}
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.cancel();
}
});
AlertDialog mCreateGroupDialog = builder.create();
mCreateGroupDialog.show();
mCreateGroupDialog.getWindow().setLayout(900, 1200);
}
private void createNewGroup(String groupName) {
Map<String, Object> groupData = new HashMap<String, Object>();
groupData.put("name", groupName);
groupData.put("adminID", currentUser.getUid());
groupData.put("users", Arrays.asList(currentUser.getUid()));
db.collection("users")
.document(currentUser.getUid())
.collection("groups")
.document(groupName)
.set(groupData)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(getContext(), "Group created successfully", Toast.LENGTH_SHORT).show();
sendUserToGroupConversation();
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.w(MainActivity.TAG, "Error adding document", e);
Toast.makeText(getActivity(), "There was an error processing the request.",
Toast.LENGTH_SHORT).show();
}
});
}
private void sendUserToGroupConversation() {
// TODO
}
}
Group.java
package com.example.snakemessenger;
import java.util.List;
class Group {
private String name;
private String adminID;
private List<String> users;
public Group() {
}
public Group(String name, String adminID, List<String> users) {
this.name = name;
this.adminID = adminID;
this.users = users;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAdminID() {
return adminID;
}
public void setAdminID(String adminID) {
this.adminID = adminID;
}
public List<String> getUsers() {
return users;
}
public void setUsers(List<String> users) {
this.users = users;
}
}
GroupsAdapter.java
package com.example.snakemessenger;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
class GroupsAdapter extends RecyclerView.Adapter<GroupsViewHolder> {
private Context mContext;
private List<Group> mGroups;
public GroupsAdapter(Context mContext, List<Group> mGroups) {
this.mContext = mContext;
this.mGroups = mGroups;
}
@NonNull
@Override
public GroupsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(mContext)
.inflate(R.layout.group_item, parent, false);
return new GroupsViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull GroupsViewHolder holder, int position) {
Group currentGroup = mGroups.get(position);
holder.getTextViewName().setText(currentGroup.getName());
holder.getCircleImageViewGroup().setImageResource(R.drawable.group_image);
}
@Override
public int getItemCount() {
return mGroups.size();
}
}
GroupsViewHolder.java
package com.example.snakemessenger;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import de.hdodenhof.circleimageview.CircleImageView;
class GroupsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView mGroupName;
private CircleImageView mGroupImage;
public GroupsViewHolder(@NonNull View itemView) {
super(itemView);
mGroupName = itemView.findViewById(R.id.group_name_item);
mGroupImage = itemView.findViewById(R.id.group_image_item);
itemView.setOnClickListener(this);
}
public TextView getTextViewName() {
return mGroupName;
}
public CircleImageView getCircleImageViewGroup() {
return mGroupImage;
}
@Override
public void onClick(View view) {
// TODO
}
}
And here are the XML files:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="@+id/main_page_toolbar"
layout="@layout/app_bar_layout">
</include>
<com.google.android.material.tabs.TabLayout
android:id="@+id/main_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:tabIndicatorColor="#FFFFFF"
app:tabMode="fixed"
app:tabGravity="fill">
</com.google.android.material.tabs.TabLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/main_tabs_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
app_bar_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
</androidx.appcompat.widget.Toolbar>
fragment_groups.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".GroupsFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/groups_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/create_group_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:fabSize="normal"
android:backgroundTint="@color/colorPrimary"
android:elevation="6dp"
android:src="@drawable/ic_group_add_black_24dp"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
group_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_gravity="start"
android:id="@+id/group_image_item"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/group_image"/>
<LinearLayout
android:layout_marginStart="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/group_name_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="25sp"
android:textStyle="bold"
android:text="Contact Name"/>
</LinearLayout>
</LinearLayout>
I am sorry for the long post but I don't know how could I explain the problem in less words. I provided you all the code because I am not sure where the problem could be. As I said, the list is displayed only when the user clicks on the FAB in order to create a new group, after clicking on the EditText in order to pick a name. Please help. Thank you!
On your GroupFragment.java class
please layout provide orientation to recylerview
change this
RecyclerView.LayoutManager layoutManager =
new LinearLayoutManager(getActivity());
mGroupsRecyclerView.setLayoutManager(layoutManager);
into this
RecyclerView.LayoutManager layoutManager =
new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL,false);
mGroupsRecyclerView.setLayoutManager(layoutManager);
or you change this through XML
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
Lets start by doing this:
do you see this method:
setAdapter();
move it from this method:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
..........
..........
setAdapter();
put it inside the get request to the database:
groups = new ArrayList<>();
db.collection("users")
.document(currentUser.getUid())
.collection("groups")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
groups.add(document.toObject(Group.class));
}
//here
setAdapter();
Toast.makeText(getActivity(), "Groups received successfully", Toast.LENGTH_SHORT).show();
} else {
Log.d(MainActivity.TAG, "Error getting document: ", task.getException());
Toast.makeText(getContext(), "Failed getting groups", Toast.LENGTH_SHORT).show();
}
}
});
And then move the get request and everything with it from onCreate to onCreateView exactly where setAdapter() was.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.