首页 > 解决方案 > RecyclerView 项目未填充(AndroidStudio、Room、MVVM)

问题描述

除了本周末等待我们的两场史诗般的战斗之外,我还有一场额外的悲剧。我正在尝试为我的投资组合创建一个健身追踪应用程序。

在应用程序中,一切似乎都很好——AndroidStudios 的模拟器清楚地显示了 RecyclerView 元素(我将深色背景和奇怪的边距设置为清晰可见)。并且数据库似乎正在正确填充。但似乎没有项目会填充 RecyclerView。在这一点上,我只是想让他们读“你好”,但他们最终需要存储客户端数据。(在尝试从后一种情况切换到前一种情况以简化问题时,我可能会感到困惑......)

AdminListActivity

public class AdminListActivity extends AppCompatActivity {
    public static final int NEW_USER_ACTIVITY_REQUEST_CODE = 1;
    private ViewModel mViewModel;
    private List<User> mUsers;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_admin_list);

        RecyclerView recyclerView = findViewById(R.id.admin_recycler_view);
        final UserListAdapter adapter = new UserListAdapter(this, mUsers);
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        // Get ViewModel from ViewModelProvider
        mViewModel = ViewModelProviders.of(this).get(ViewModel.class);

        // Observer on LiveData returned by getAllUsers.
        mViewModel.getAllUsers().observe(this, new Observer<List<User>>() {
            @Override
            public void onChanged(@Nullable final List<User> users) {
                // Update the cached copy of the words in the adapter.
                adapter.setUsers(users);
            }
        });
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == NEW_USER_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
            User user = new User(data.getStringExtra(RegisterFragment.EXTRA_REPLY));
            mViewModel.addUser(user);
        } else {
            Toast.makeText(
                    getApplicationContext(),
                    "not saved",
                    Toast.LENGTH_LONG).show();
        }
    }
}

管理列表片段


public class AdminListFragment extends Fragment implements View.OnClickListener {

    private RecyclerView mUserRecyclerView;
    private Button mAddNewClient;

    public AdminListFragment() {}

    @Override
    public void onClick(View v) {
        // required onClick method
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_admin_list, container, false);

        mUserRecyclerView = (RecyclerView) view.findViewById(R.id.admin_recycler_view);
        mUserRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        setHasOptionsMenu(true);
        mAddNewClient = view.findViewById(R.id.add_new_client);
        return view;

    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        menu.clear();
        inflater.inflate(R.menu.fragment_admin_list, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.add_new_client:              SingleFragmentActivity.fm.beginTransaction().replace(R.id.fragment_container,
                        new RegisterFragment()).addToBackStack(null).commit();
                // TODO: OR: add from contacts
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
}

用户列表适配器

public class UserListAdapter extends RecyclerView.Adapter<UserListAdapter.UserViewHolder> {
    private LayoutInflater mInflater = null;
    private List<User> mUsers = Collections.emptyList(); // Cached copy of users

    public UserListAdapter(Context context, List<User> mUsers) {
        mInflater = LayoutInflater.from(context);
    }

    void setUsers(List<User> users) {
        mUsers = users;
        notifyDataSetChanged();
    }

    class UserViewHolder extends RecyclerView.ViewHolder {
        private TextView userListItem;

        public UserViewHolder(View itemView) {
            super(itemView);
            userListItem = itemView.findViewById(R.id.userListItem);
        }
    }

    @Override
    public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = mInflater.inflate(R.layout.recyclyerview_user_list_item, parent, false);
        return new UserViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(UserViewHolder holder, int position) {
        User current = mUsers.get(position);
        holder.userListItem.setText(current.getClientName());
    }

    // getItemCount() is called many times, and when it is first called,
    // mUsers has not been updated (means initially, it's null, and we can't return null).
    @Override
    public int getItemCount() {
        return mUsers.size();

    }
}

视图模型

public class ViewModel extends AndroidViewModel {

    private UserDao mUserDao;
    public Repository mRepository;
    public LiveData<List<User>> mAllUsers;

    public ViewModel (Application application) {
        super(application);
        mRepository = new Repository(application);
        mAllUsers = mRepository.getAllUsers();
    }

    public LiveData<List<User>> getAllUsers() { return mAllUsers; }

    public void addUser(User user) { mRepository.addUser(user); }

}

存储库

public class Repository {

    private UserDao mUserDao;
    private LiveData<List<User>> mAllUsers;

    public Repository(Application application) {
        UserDatabase db = UserDatabase.buildDatabase(application);
        mUserDao = db.userDao();
        mAllUsers = mUserDao.getAllUsers();
    }

    public LiveData<List<User>> getAllUsers() {
        return mAllUsers;
    }

    public void addUser(User user) {
        new insertAsyncTask(mUserDao).execute(user);
    }

    private static class insertAsyncTask extends AsyncTask<User, Void, Void> {

        private UserDao mAsyncTaskDao;

        insertAsyncTask(UserDao dao) {
            mAsyncTaskDao = dao;
        }

        @Override
        protected Void doInBackground(final User... params) {
            mAsyncTaskDao.addUser(params[0]);
            return null;
        }
    }
}

列表项的 XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/userListItem"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        android:layout_marginTop="300dp"
        android:text="HELLO"
        android:textColor="#000000"
        android:visibility="visible"
        tools:visibility="visible" />

</LinearLayout>

片段中 recyclerview 的 XML:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="admin.AdminListFragment">

    <androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/admin_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:background="@android:color/darker_gray"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:listitem="@layout/recyclyerview_user_list_item" />

</androidx.constraintlayout.widget.ConstraintLayout>

用户数据库

@Database(entities = {User.class, Admin.class}, version = 6, exportSchema = false)
public abstract class UserDatabase extends RoomDatabase {
    private static volatile UserDatabase INSTANCE;
    public abstract UserDao userDao();
    public static final String SP_NAME = "users";

    public static UserDatabase buildDatabase(final Context context) {
        if (INSTANCE == null) {
            synchronized (UserDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(), UserDatabase.class, "users").build();
                }
            }
        }
        return INSTANCE;
    }

    /**
     * Override the onOpen method to populate the database.
     * For this sample, we clear the database every time it is created or opened.
     *
     * If you want to populate the database only when the database is created for the 1st time,
     * override RoomDatabase.Callback()#onCreate
     */
    private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {

        @Override
        public void onOpen(@NonNull SupportSQLiteDatabase db) {
            super.onOpen(db);
            // If you want to keep the data through app restarts,
            // comment out the following line.
            new PopulateDbAsync(INSTANCE).execute();
        }
    };

    /**
     * Populate the database in the background.
     * If you want to start with more words, just add them.
     */
    private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {

        private final UserDao mDao;

        PopulateDbAsync(UserDatabase db) {
            mDao = db.userDao();
        }

        @Override
        protected Void doInBackground(final Void... params) {
            // Start the app with a clean database every time.
            // Not needed if you only populate on creation.
            //mDao.deleteAll();

            User user = new User("Dickon", "d");
            mDao.addUser(user);
            user = new User("Pumpy", "d");
            mDao.addUser(user);
            return null;
        }
    }
}

用户道

package database;

import java.util.List;

import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import User.User;
import admin.Admin;

@Dao
public interface UserDao {

    @Insert
    void addUser(User user);

    @Insert
    void createAdmin(Admin admin);

    @Query("select * from users")
    LiveData<List<User>> getUser();

    @Query
    ("SELECT * from users ORDER BY clientName")
    LiveData<List<User>> getAllUsers();

    @Query("select * FROM users WHERE id = :id")
    List<User> getUserById(int id);

    @Query("select * FROM users WHERE clientName = :clientName LIMIT 1")
    List<User> getUserByName(String clientName);

    @Delete
    void DeleteUser(User user);
}

标签: androidandroid-recyclerview

解决方案


在您的 AdminListActivity 中,您有

   setContentView(R.layout.fragment_admin_list);

   RecyclerView recyclerView = findViewById(R.id.admin_recycler_view);
   final UserListAdapter adapter = new UserListAdapter(this, mUsers);
   recyclerView.setAdapter(adapter);
   recyclerView.setLayoutManager(new LinearLayoutManager(this));

在你的 AdminListFragment

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_admin_list, container, false);

    mUserRecyclerView = (RecyclerView) view.findViewById(R.id.admin_recycler_view);
    mUserRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    ...
}

recyclerView来自您的片段与来自recyclerView您的活动的不同。因此,您可以在 Activity 中看到用户,但在 Fragment 中看不到。您的片段recyclerView没有适配器。


推荐阅读