我有一个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
{
...
}
答案 0 :(得分:0)
在Java中没有错误。布局定义中的GUI新手错误表示,每页将显示一组。将TextView layout_height更改为“ wrap_content”。