我目前正在开发一个类似 WhatsApp 的 Android 应用程序,最近遇到了一个让我头疼的问题。我正在尝试在属于 TabLayout 的 Fragment 内创建 RecyclerView。基本上,我有 3 个选项卡,每个选项卡都包含一个 Fragment。第一个选项卡用于用户的对话,第二个选项卡用于组,第三个选项卡用于联系人。每个选项卡都应包含一个 RecyclerView,它根据 Firebase 身份验证提供的当前用户 ID 显示来自 Firebase Firestore 的数据。我认为问题在于,除了 RecyclerView 之外,Fragment 内部还有一个 FloatingActionButton。此按钮在每个 fragment 中用于执行发送新消息或创建新组或添加新联系人等操作。单击时,假设在组选项卡内,FAB 将显示一个 AlertDialog,要求用户填写组名称,然后选择“创建”,然后将创建该组并将其添加到数据库中。现在的问题是,当用户登录应用程序并访问“组”选项卡时,不会显示其组,但如果用户单击 FAB,则会出现 AlertDialog,并且如果用户单击 EditText 以选择名称对于新组,用户的组突然显示在 fragment 内。我需要一些帮助,我对 Android 没有太多经验,我认为我搞乱了布局,但我自己无法真正弄清楚。
这是我的代码:
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
}
}
这是 XML 文件:
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>
很抱歉这篇文章很长,但我不知道如何用更少的语言解释这个问题。我向您提供了所有代码,因为我不确定问题出在哪里。 正如我所说,仅当用户单击 FAB 以创建新组、单击 EditText 以选择名称后,才会显示该列表。 请帮忙。谢谢!
最佳答案
让我们开始这样做:
你看到这个方法了吗:
setAdapter();
从此方法中移动它:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
..........
..........
setAdapter();
将其放入对数据库的 get 请求中:
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();
}
}
});
然后将获取请求及其所有内容从 onCreate 移至 onCreateView 正是 setAdapter() 所在的位置。
关于java - Fragment 内的 RecyclerView 未正确显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61296082/