Realm和RecyclerView项目排序和自动ViewPager片段通信
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Realm和RecyclerView项目排序和自动ViewPager片段通信相关的知识,希望对你有一定的参考价值。
我现在面临一些问题,但是我很难解决。所以我指的是社区中的Realm和RecyclerView天才。我正在使用ToDo-List,它将完成的任务在2天后重新设置为ToDo-List。该应用程序使用带有两个选项卡的ViewPager:“TODO”和“DONE”。
1. RecyclerView
1.1。我希望片段1中已完成的任务在2天后自动发送回片段0。问题:如果计数器为0(或低于),则项目将被发送到片段0.如果我在下一行中删除项目,则会出现异常错误:"java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling"
所以我将删除函数放入处理程序中。然后只有当一个人被送回时它才能正常工作。如果同时发回许多项目,应用程序崩溃。当我重新打开应用程序时,一切正常,因为它已成功保存在领域中,但一个项目始终保存两次。问题出在哪里(在DoneAdapter.java中)?
2.境界
2.1。当我将一个Item添加到RecyclerView(同时添加到Realm)时,该项将添加到底部。但我想在位置0添加每个新项目。(我知道如何用ArrayList实现这个,但我希望在重新打开应用程序时存储和显示项目,所以我使用的是Realm DB。)你有任何建议来实现这一目标吗?
2.2。是否可以稍后在onLongClickListener上实现拖放项目并使用Realm重新排列位置? (我想用这个https://www.youtube.com/watch?v=tNgevYpyA9E)
2.3。我想在添加和检查项目时添加一些不错的动画。 Realm不支持mRecyclerView.setItemAnimator(...);
但我听说可以添加mAdapter.setHasStableIds(true);
。不幸的是它引发了一个例外:java.lang.IllegalStateException: Cannot change whether this adapter has stable IDs while the adapter has registered observers.
(你可以在下面的代码中看到这个)你有任何解决方案吗?
(可选1.4。你能推荐我可以与Realm同步的任何在线数据库(例如Firebase)吗?或者更普遍的是:是否可以将在线数据库与Realm同步?你知道任何教程(Udemy,YouTube)来设置这个吗?同步过程?)
最后:我想每隔午夜使用后台服务更新数据库,因此已完成部分中的计数器会自动更新。有谁知道怎么做?也许与protected void onHandleIntent(Intent intent)
?你也知道调试模式中是否有一个选项可以模拟通过时间?
这是代码:
main activity.Java
public class MainActivity extends AppCompatActivity implements ToOtherFragmentCommunicator {
private ViewPagerAdapter mViewPagerAdapter;
private ViewPager mViewPager;
private static final int DONE = 1;
private static final int TODO = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mViewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mViewPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
mViewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
RealmConfiguration configuration = new RealmConfiguration.Builder(this).build();
Realm.setDefaultConfiguration(configuration);
}
@Override
public void itemToOtherFragment(String data, int fragment) {
if (DONE == fragment) {
Done done = (Done) mViewPagerAdapter.getItem(fragment);
done.createDoneItem(data);
} else if (TODO == fragment) {
ToDo toDo = (ToDo) mViewPagerAdapter.getItem(fragment);
toDo.createToDoItem(data);
}
}
}
to do.Java
public class ToDo extends Fragment {
private RecyclerView mRecyclerView;
private ToDoAdapter mAdapter;
private EditText taskInput;
private String taskName;
private Realm mRealm;
private RealmResults<ListItems> mResults;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View toDoView = inflater.inflate(R.layout.todo_layout, container, false);
mRecyclerView = (RecyclerView) toDoView.findViewById(R.id.todo_rv);
mRealm = Realm.getDefaultInstance();
mResults = mRealm.where(ListItems.class).equalTo("fragment", 0).findAllAsync();
setRecyclerView();
mRecyclerView.setItemAnimator(null);
//TODO add product to shopping list
final Handler handler = new Handler();
taskInput = (EditText) toDoView.findViewById(R.id.task_input);
taskInput.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (taskInput.getText().length() > 0 && (event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
// Perform action on key press
taskName = taskInput.getText().toString();
//Problem 2.1
//Code for adding item at the top with mRealm?
mRealm.beginTransaction();
createToDoItem(taskName);
mRealm.commitTransaction();
// mRecyclerView.scrollToPosition(0);
taskInput.setText(null);
handler.postDelayed(new Runnable() {
@Override
public void run() {
taskInput.setFocusableInTouchMode(true);
taskInput.setFocusable(true);
taskInput.requestFocus();
}
}, 200);
return true;
} else if (taskInput.length() == 0 && (event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
taskInput.clearFocus();
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(taskInput.getWindowToken(), 0);
return true;
}
return false;
}
});
return toDoView;
}
//TODO creates the shopping list item in DB
public void createToDoItem(String taskName) {
ListItems item = mRealm.createObject(ListItems.class);
long now = System.currentTimeMillis();
item.setAddedTime(now);
item.setFragment(0);
item.setTaskName(taskName);
mRealm.copyToRealmOrUpdate(item);
}
public void setRecyclerView() {
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new ToDoAdapter(getActivity(), mRealm, mResults);
mRecyclerView.setAdapter(mAdapter);
//Problem 2.3.
//Produces "java.lang.IllegalStateException: Cannot change whether this adapter has stable IDs while the adapter has registered observers."
// mAdapter.setHasStableIds(true);
}
private RealmChangeListener mChangeListener = new RealmChangeListener() {
@Override
public void onChange() {
mAdapter.updateItems(mResults);
}
};
@Override
public void onStart() {
super.onStart();
mResults.addChangeListener(mChangeListener);
}
@Override
public void onStop() {
super.onStop();
mResults.removeChangeListener(mChangeListener);
}
}
to do adapter.Java
public class ToDoAdapter extends RecyclerView.Adapter<ListItemsViewHolder> {
private Context mContext;
private Realm mRealm;
private RealmResults<ListItems> mResults;
private int focusedItem = 0;
ToOtherFragmentCommunicator comm;
ToDoAdapter(Context context, Realm realm, RealmResults<ListItems> mResults) {
this.mContext = context;
this.mRealm = realm;
updateItems(mResults);
}
public void updateItems(RealmResults<ListItems> mResults) {
this.mResults = mResults;
notifyDataSetChanged();
}
//Problem 2.3.
//needed for mAdapter.setHasStableIds(true); in ToDo.java
// @Override
// public long getItemId(int position) {
// if (position < mResults.size()) {
// return mResults.get(position).getAddedTime();
// } else {
// return RecyclerView.NO_ID;
// }
// }
@Override
public ListItemsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.todo_item, parent, false);
comm = (ToOtherFragmentCommunicator) mContext;
return new ListItemsViewHolder(v);
}
@Override
public void onBindViewHolder(final ListItemsViewHolder holder, final int position) {
final ListItems items = mResults.get(position);
holder.taskName.setText(items.getTaskName());
holder.itemView.setSelected(focusedItem == position);
holder.getLayoutPosition();
holder.itemCheckbox.setOnCheckedChangeListener(null);
holder.itemCheckbox.setChecked(items.isSelected());
holder.itemCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mRealm.beginTransaction();
items.setSelected(isChecked);
//send item to Done
comm.itemToOtherFragment(items.getTaskName(), 1);
removeItem(position);
mRealm.commitTransaction();
}
});
}
@Override
public int getItemCount() {
return (mResults != null ? mResults.size() : 0);
}
private void removeItem(int position) {
mResults.get(position).removeFromRealm();
notifyDataSetChanged();
}
}
done.Java
public class Done extends Fragment {
private RecyclerView mRecyclerView;
private DoneAdapter mAdapter;
private Calendar calendar = Calendar.getInstance();
private Date date = new Date();
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy");
private Realm mRealm;
private RealmResults<ListItems> mResults;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View doneView = inflater.inflate(R.layout.done_layout, container, false);
mRecyclerView = (RecyclerView) doneView.findViewById(R.id.done_rv);
mRealm = Realm.getDefaultInstance();
mResults = mRealm.where(ListItems.class).equalTo("fragment", 1).findAllAsync();
setRecyclerView();
mRecyclerView.setItemAnimator(null);
return doneView;
}
//TODO creates the fridge item in DB
public void createDoneItem(String taskName) {
TimeZone.getDefault();
ListItems item = mRealm.createObject(ListItems.class);
long now = System.currentTimeMillis();
item.setAddedTime(now);
item.setFragment(1);
item.setTaskName(taskName);
item.setInputDate(simpleDateFormat.format(calendar.getTime()));
calendar.add(Calendar.DATE, 2);
item.setRenewDate(simpleDateFormat.format(calendar.getTime()));
//reset time to current date after adding days
calendar.setTime(date);
item.getRenewDate();
mRealm.copyToRealmOrUpdate(item);
}
public void setRecyclerView() {
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new DoneAdapter(getActivity(), mRealm, mResults, Done.this);
mRecyclerView.setAdapter(mAdapter);
}
private RealmChangeListener mChangeListener = new RealmChangeListener() {
@Override
public void onChange() {
mAdapter.updateItems(mResults);
}
};
@Override
public void onStart() {
super.onStart();
mResults.addChangeListener(mChangeListener);
}
@Override
public void onStop() {
super.onStop();
mResults.removeChangeListener(mChangeListener);
}
}
done adapter.Java
public class DoneAdapter extends RecyclerView.Adapter<ListItemsViewHolder> {
private Context mContext;
private Done done;
private Realm mRealm;
private RealmResults<ListItems> mResults;
private int focusedItem = 0;
protected ToOtherFragmentCommunicator comm;
DoneAdapter(Context context, Realm realm, RealmResults<ListItems> results, Done done) {
this.mContext = context;
this.mRealm = realm;
this.done = done;
updateItems(results);
}
public void updateItems(RealmResults<ListItems> mResults) {
this.mResults = mResults;
notifyDataSetChanged();
}
@Override
public ListItemsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.done_item, parent, false);
comm = (ToOtherFragmentCommunicator) mContext;
return new ListItemsViewHolder(v);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onBindViewHolder(final ListItemsViewHolder holder, final int position) {
final ListItems items = mResults.get(position);
holder.taskName.setText(items.getTaskName());
try {
if (items.getRenewCounter() == 1) {
holder.renewCounter.setText(mContext.getString(R.string.show_days_till_renew, items.getRenewCounter(), mContext.getString(R.string.day)));
} else {
holder.renewCounter.setText(mContext.getString(R.string.show_days_till_renew, items.getRenewCounter(), mContext.getString(R.string.days)));
}
holder.renewCounter.setTextColor(ContextCompat.getColor(mContext, R.color.colorAccent));
if (items.getRenewCounter() <= 0) {
mRealm.beginTransaction();
//Problem 1.1.
//send item back to todo list
comm.itemToOtherFragment(items.getTaskName(), 0);
// Produces "java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling" if there is no Handler
Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
mRealm.beginTransaction();
removeItem(position);
mRealm.commitTransaction();
}
};
handler.post(r);
mRealm.commitTransaction();
}
} catch (ParseException e) {
e.printStackTrace();
}
holder.itemView.setSelected(focusedItem == position);
holder.getLayoutPosition();
}
@Override
public int getItemCount() {
return (mResults != null ? mResults.size() : 0);
}
private void removeItem(int position) {
mResults.get(position).removeFromRealm();
notifyDataSetChanged();
}
}
list items.Java
public class ListItems extends RealmObject {
public ListItems(long addedTime, String taskName, String inputDate, String renewDate, int fragment) {
this.addedTime = addedTime;
this.taskName = taskName;
this.inputDate = inputDate;
this.renewDate = renewDate;
this.fragment = fragment;
}
@PrimaryKey
private long addedTime;
private int fragment;
@Ignore
private long renewCounter;
private String taskName, inputDate, renewDate;
private boolean selected;
public ListItems() {
}
public long getAddedTime() {
return addedTime;
}
public void setAddedTime(long addedTime) {
this.addedTime = addedTime;
}
public int getFragment() {
return fragment;
}
public void setFragment(int fragment) {
this.fragment = fragment;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public String getInputDate() {
return inputDate;
}
public void setInputDate(String inputDate) {
this.inputDate = inputDate;
}
public String getRenewDate() {
return renewDate;
}
public void setRenewDate(String renewDate) {
this.renewDate = renewDate;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public long getRenewCounter() throws ParseException {
TimeZone.getDefault();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
Date todayDate = new Date();
Date exDate = dateFormat.parse(renewDate);
this.renewCounter = daysBetween(todayDate, exDate);
return renewCounter;
}
private static long daysBetween(Date startDate, Date endDate) {
Calendar sDate = getDatePart(startDate);
Calendar eDate = getDatePart(endDate);
long daysBetween = 0;
while (sDate.before(eDate)) {
sDate.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
while (eDate.before(sDate)) {
eDate.add(Calendar.DAY_OF_MONTH, 1);
daysBetween--;
}
return daysBetween;
}
private static Calendar getDatePart(Date date) {
Calendar cal = Calendar.getInstance(); // get calendar instance
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0); // set hour to midnight
cal.set(Calendar.MINUTE, 0); // set minute in hour
cal.set(Calendar.SECOND, 0); // set second in minute
cal.set(Calendar.MILLISECOND, 0); // set millisecond in second
return cal; // return the date part
}
}
这是一个关于应用程序外观的截图:DailyTaskRepeater
而已!如果有人可以帮助我解决所有问题(特别是问题1.1!),这对我来说意味着世界。
谢谢!
Realm支持的当前做法是添加索引(例如时间戳)并对列表进行反向排序,以使最新项目位于顶部,并获得您正在寻找的重新排列效果。
请考虑参考官方存储库中提供的an adapter example。
以上是关于Realm和RecyclerView项目排序和自动ViewPager片段通信的主要内容,如果未能解决你的问题,请参考以下文章
将水平 RecyclerView 作为项目放置在垂直 RecyclerView 中时的自动滚动问题