我不知道为什么我的列表视图没有按预期更新

时间:2019-02-20 10:29:52

标签: android mvvm android-recyclerview recycler-adapter

我有一个Fragment,其中包含一个RecyclerView,用于来自数据库的items(组)列表。用户可以导航到单独的页面以创建新组。在该操作中,该组通过带有asynchronous任务的存储库插入数据库。在此期间,用户将返回到包含列表的页面,因此将调用onResume的{​​{1}}方法。插入记录数据库操作完成后,存储库将新列表发布到Fragment中。组列表的适配器已更新,但视图未更新。我不知道为什么我以为我正确地遵循了MVVM模式。

这是记录器的输出,显示插入操作在LiveData之后完成。按预期,将调用onResume方法来更新列表。在这种情况下,“ GroupListAdapter:SetGroups 2”表示2个组,在用户创建第二个之前先有1个。

GroupListAdapter

以下是涉及的类。 片段:

HomeFragment onAttach
HomeFragment onCreate
HomeFragment onCreateView
GroupsFragment onAttach
GroupsFragment onCreate
GroupsFragment initData
GroupListViewModel created
GroupsFragment onCreateView
GroupsFragment: Do group list view
GroupsFragment list changed
GroupListAdapter: setGroups null
GroupListAdapter: setGroups inserted
GroupsFragment: Do group list view
GroupsFragment onResume
GroupsFragment: Do group list view
Repository: on group list change.
GroupsFragment list changed
GroupListAdapter: setGroups 1
GroupListAdapter: setGroups inserted
GroupsFragment: Do group list view
GroupsFragment list changed
GroupListAdapter: setGroups 0
GroupListAdapter dispatch updates

GroupListAdapter: setGroups 1 <<<<<<<<<< Initially 1 item in the group
GroupListAdapter dispatch updates
GroupsFragment: Do group list view
Finish create group activity. Result: Intent { (has extras) }
MainActivity onActivityResult for request 6, result: -1
Handle result of create group activity.
GroupListViewModel created
GroupListViewModel insert group
Created insert group task.
Async insert group.
Group inserted. <<<<<<<<<<<<<<<<<<<<<<< insertion completes before fragment's onResume
GroupsFragment onResume
GroupsFragment: Do group list view
Repository: on group list change.
GroupsFragment list changed
GroupListAdapter: setGroups 2 <<<<<<<<<<<<< The adapter knows there are 2 items in the list
GroupListAdapter dispatch updates
GroupsFragment: Do group list view  >>>>>>>>>>>>>>>> Fragment should update, but does not.

ViewModel:

public class GroupsFragment extends Fragment
{
private Context m_context = null;
private RecyclerView rv_groups;
private GroupListAdapter adapter = null;
private TextView tv_noGroups;

private GroupListViewModel m_groupViewModel;

public GroupsFragment ()
{} // Required empty public constructor

@Override
public void onAttach (Context context)
{
    Logger.get().fine("GroupsFragment onAttach");
    super.onAttach(context);
    m_context = context;
}

@Override
public void onCreate (@Nullable Bundle savedInstanceState)
{
    Logger.get().fine("GroupsFragment onCreate");
    super.onCreate(savedInstanceState);
    initData();
}

private void initData ()
{
    Logger.get().fine("GroupsFragment initData");
    m_groupViewModel = ViewModelProviders.of(this).get(GroupListViewModel.class);
    if (m_groupViewModel.getAllGroups() == null)
        Logger.get().severe("null group list live data in viewmodel");
    m_groupViewModel.getAllGroups().observe(this, groups -> {
        Logger.get().fine("GroupsFragment list changed");
        adapter.setGroups(groups); // FIXME: Shouldn't this cause view update?
        doListView(); // FIXME: Shouldn't need this?
    });
}

@Override
public View onCreateView (@NonNull LayoutInflater inflater, ViewGroup container,
                          Bundle savedInstanceState)
{
    Logger.get().fine("GroupsFragment onCreateView");
    View view = inflater.inflate (R.layout.fragment_groups, container, false);

    adapter = new GroupListAdapter(m_context);

    initListView(view);
    FloatingActionButton fab_add;
    fab_add = view.findViewById(R.id.fab_add);
    fab_add.setOnClickListener (v -> {
        // FIXME: getActivity may return null if fragment is associated with Context, not Activity
        getActivity().startActivityForResult(new Intent(getContext(), CreateGroupActivity.class), Activities.CREATE_GROUP);
    });
    setHasOptionsMenu (true);
    return view;
}

protected void initListView (View view)
{
    rv_groups = view.findViewById(R.id.rv_groups);
    rv_groups.setAdapter(adapter);
    tv_noGroups = view.findViewById(R.id.tv_noGroups);
    RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(m_context);
    rv_groups.setLayoutManager(mLayoutManager);
    rv_groups.setItemAnimator(new DefaultItemAnimator());
    rv_groups.addItemDecoration(new DividerItemDecoration(m_context, DividerItemDecoration.VERTICAL));
    doListView();
}

/** Indicate on the UI that there are no groups to display. */
private void showNoGroups ()
{
    rv_groups.setVisibility(View.GONE);
    tv_noGroups.setVisibility(View.VISIBLE);
    tv_noGroups.setText(getResources().getString(R.string.string_noGroups));
}

private void doListView ()
{
    Logger.get().fine("GroupsFragment: Do group list view");
    if (m_groupViewModel == null || m_groupViewModel.countGroups() == 0)
    {
        showNoGroups();
    }
    else
    {
        rv_groups.setVisibility(View.VISIBLE);
        tv_noGroups.setVisibility(View.GONE);
    }
}

@Override
public void onResume ()
{
    Logger.get().fine("GroupsFragment onResume");
    super.onResume();
    doListView();
}
}

适配器:

public class GroupListViewModel extends AndroidViewModel
{
private final Repository m_repository;
private final MediatorLiveData<List<GroupEntity>> m_groups;

public GroupListViewModel (@NonNull Application application)
{
    super(application);
    m_groups = new MediatorLiveData<>();
    // set null until we get data from the database.
    m_groups.setValue(null);
    m_repository = ((MyApp)application).getRepository();
    LiveData<List<GroupEntity>> groups = m_repository.getAllGroups();
    // observe the changes of the groups from the database and forward them
    m_groups.addSource(groups, m_groups::setValue);
    Logger.get().finer("GroupListViewModel created");
}

public int countGroups ()
{
    if (m_groups.getValue() == null)
        return 0;
    return m_groups.getValue().size();
}

public LiveData<List<GroupEntity>> getAllGroups ()
{ return m_groups; }

public List<GroupEntity> searchGroups (String query)
{ return m_repository.searchGroups(query); }

public void insert (GroupEntity group)
{
    Logger.get().finer("GroupListViewModel insert group");
    m_repository.insertGroup(group);
}

public void update (GroupEntity group)
{
    Logger.get().finer("GroupListViewModel update group");
    m_repository.updateGroup(group);
}
}

存储库:

public class GroupListAdapter extends RecyclerView.Adapter<GroupListAdapter.GroupViewHolder>
{
private List<? extends Group> m_groupList;

private Context context;

public GroupListAdapter (Context context)
{
    this.context = context;
}

class GroupViewHolder extends RecyclerView.ViewHolder
{
    TextView name;
    LinearLayout lay_group;

    GroupViewHolder (View itemView)
    {
        super(itemView);
        name = itemView.findViewById(R.id.tv_name);
        lay_group = itemView.findViewById(R.id.lay_groups);
    }
}

@Override
@NonNull
public GroupViewHolder onCreateViewHolder (@NonNull ViewGroup parent, int viewType)
{
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_groups, parent, false);
    return new GroupViewHolder(view);
}

@Override
public void onBindViewHolder (@NonNull final GroupViewHolder holder, int position)
{
    final Group group = m_groupList.get(position);
    holder.name.setText(group.getName());
    // Set listener to show group details when group in list is clicked
    holder.lay_group.setOnClickListener(v -> {
        Intent intent = new Intent(context, GroupDetailActivity.class);
        Logger.get().fine("Start group details activity for id " + group.getId());
        intent.putExtra(GroupEntity.GROUP_ID_KEY, group.getId());
        context.startActivity(intent);
    });
}

public void setGroups (@Nullable final List<? extends Group> groups)
{
    Logger.get().fine("GroupListAdapter: setGroups "  + (groups == null ? "null" : groups.size()));
    if (m_groupList == null)
    {
        m_groupList = groups;
        notifyItemRangeInserted(0, groups == null ? 0 : groups.size());
        Logger.get().fine("GroupListAdapter: setGroups inserted");
        return;
    }
    DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback()
    {
        @Override
        public int getOldListSize ()
        { return m_groupList.size(); }

        @Override
        public int getNewListSize ()
        { return groups.size(); }

        @Override
        public boolean areItemsTheSame (int oldItemPosition, int newItemPosition)
        { return m_groupList.get(oldItemPosition).getId() == groups.get(newItemPosition).getId(); }

        @Override
        public boolean areContentsTheSame (int oldItemPosition, int newItemPosition)
        {
            Group newGroup = groups.get(newItemPosition);
            Group oldGroup = m_groupList.get(oldItemPosition);
            return newGroup.getId() == oldGroup.getId()
                    && (CommonUtils.equalStrings(newGroup.getName(), oldGroup.getName()));
        }
    });
    m_groupList = groups;
    Logger.get().finer("GroupListAdapter dispatch updates");
    result.dispatchUpdatesTo(this);
}

@Override
public int getItemCount()
{
    // Must allow for groups not completed loading yet
    if (m_groupList == null)
        return 0;
    return m_groupList.size();
}

@Override
public long getItemId (int position)
{ return m_groupList.get(position).getId(); } // Note online BasicSample example does not check for null list here.
}

组:

public class Repository
{
private static Repository sInstance;

private final Database m_database;

private GroupDAO m_groupDAO;

private MediatorLiveData<List<GroupEntity>> m_observableGroups;
//private LiveData<List<GroupEntity>> m_groups;

public static Repository getInstance (final Database database)
{
    if (sInstance == null)
    {
        synchronized (Repository.class)
        {
            if (sInstance == null)
                sInstance = new Repository(database);
        }
    }
    return sInstance;
}

private Repository (final Database database)
{
    m_database = database;
    load();
}

public Repository (Application application)
{
    this(Database.getDatabase(application));
}

/**
 * Get all data access objects.
 */
private void getDAO ()
{
    m_groupDAO = m_database.groupDAO();
}

/**
 * Get objects from the database, to store in this repository.
 */
private void load ()
{
    getDAO();
    Logger.get().info("Load objects to repository");
    m_observableGroups = new MediatorLiveData<>();
    m_observableGroups.addSource(m_database.groupDAO().loadAllSync(),
            new Observer<List<GroupEntity>>()
            {
                @Override
                public void onChanged (List<GroupEntity> groupEntities)
                {
                    Logger.get().info("Repository: on group list change.");
                    if (m_database.getDatabaseCreated().getValue() != null)
                        m_observableGroups.postValue(groupEntities);
                }
            }
    );
}

public LiveData<List<GroupEntity>> getAllGroups ()
{ return m_observableGroups; }

/*private LiveData<GroupEntity> loadGroup (final int id)
{ return m_database.groupDAO().loadById(id); }*/

// TODO which getGroup? return LiveData<GroupEntity> ?
/*public GroupEntity getGroup (int id)
{
    Logger.get().finer("Repository: getGroup.");
    for (GroupEntity group : getAllGroups().getValue())
    {
        if (group.getId() == id)
            return group;
    }
    return null;
}*/

public GroupEntity getGroup (int id)
{
    Logger.get().finer("Repository: getGroup.");
    return m_database.groupDAO().loadById(id);
}

public LiveData<GroupEntity> getGroupSync (int id)
{
    Logger.get().finer("Repository: getGroup.");
    return m_database.groupDAO().loadByIdSync(id);
}

public void insertGroup (GroupEntity group)
{ new insertGroupTask(m_groupDAO).execute(group); }

private static class insertGroupTask extends AsyncTask<GroupEntity, Void, Void>
{
    private GroupDAO mAsyncTaskDao;

    insertGroupTask(GroupDAO dao) {
        Logger.get().info("Created insert group task.");
        mAsyncTaskDao = dao;
    }

    @Override
    protected Void doInBackground (final GroupEntity... params)
    {
        Logger.get().info("Async insert group.");
        mAsyncTaskDao.insert(params[0]);
        Logger.get().fine("Group inserted.");
        return null;
    }
}
}

组实体

public interface Group
{
    ...
}

1 个答案:

答案 0 :(得分:0)

在Java中没有错误。布局定义中的GUI新手错误表示,每页将显示一组。将TextView layout_height更改为“ wrap_content”。