[英]Implementing timers in RecyclerViewAdapter
我在RecyclerView中實現倒數計時器時遇到問題。 輸入到RecyclerView的數據來自Dialog,用戶可以在其中鍵入項目名稱,設置SeekBar時間(以秒為單位)並選擇帶有自定義小部件的日期。 信息保存在Realm數據庫中。
問題是重新啟動應用程序或添加新項目后,所有項目中的所有計時器都會重新啟動並從頭開始計數。 如何實現即使在應用程序不處於活動狀態或添加新項目時也要計數的計時器。 預先感謝您的幫助。
public class AdapterDrops extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements SwipeListener {
public static final int COUNT_FOOTER = 1;
public static final int COUNT_NO_ITEMS = 1;
public static final int ITEM = 0;
public static final int NO_ITEM = 1;
public static final int FOOTER = 2;
private final ResetListener mResetListener;
private MarkListener mMarkListener;
//inflater object which converts xml file to view object
private LayoutInflater mInflater;
public RealmResults<Drop> mResults;
private AddListener mAddListener;
private int mFilterOption;
private Realm mRealm;
private Context mContext;
Handler handler;
public long duration;
public AdapterDrops(Context context, Realm realm, RealmResults<Drop> results, AddListener listener, MarkListener markListener, ResetListener resetListener) {
mContext = context;
mInflater = LayoutInflater.from(context);
update(results);
mRealm = realm;
mAddListener = listener;
mMarkListener = markListener;
mResetListener = resetListener;
}
public void update(RealmResults<Drop> results) {
mResults = results;
mFilterOption = AppBucketDrops.load(mContext);
//notification do Apdapter that database was changed
notifyDataSetChanged();
}
@Override
public long getItemId(int position) {
if (position < mResults.size()) {
return mResults.get(position).getAdded();
}
return RecyclerView.NO_ID;
}
@Override
public int getItemViewType(int position) {
if (!mResults.isEmpty()) {
if (position < mResults.size()) {
return ITEM;
} else {
return FOOTER;
}
} else {
if (mFilterOption == Filter.COMPLETE ||
mFilterOption == Filter.INCOMPLETE) {
if (position == 0) {
return NO_ITEM;
} else {
return FOOTER;
}
} else {
return ITEM;
}
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == FOOTER) {
View view = mInflater.inflate(R.layout.footer, parent, false);
//footerHolder class which we created below
return new FooterHolder(view);
} else if (viewType == NO_ITEM) {
View view = mInflater.inflate(R.layout.no_item, parent, false);
return new NoItemsHolder(view);
} else {
//layourInflater converts xml file to java View object
View view = mInflater.inflate(R.layout.row_drop, parent, false);
return new DropHolder(view, mMarkListener);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof DropHolder) {
DropHolder dropHolder = (DropHolder) holder;
//returning an item from the paricular position
Drop drop = mResults.get(position);
//seting MtextView to proper drop.getWhat text
dropHolder.setWhat(drop.getWhat());
dropHolder.setWhen(drop.getWhen());
dropHolder.setTimer(drop.getTimer());
dropHolder.setBackground(drop.isCompleted());
}
}
@Override
public int getItemCount() {
if (!mResults.isEmpty()) {
return mResults.size() + COUNT_FOOTER;
} else {
if (mFilterOption == Filter.LEAST_TIME_LEFT
|| mFilterOption == Filter.MOST_TIME_LEFT
|| mFilterOption == Filter.NONE) {
return 0;
} else {
return COUNT_NO_ITEMS + COUNT_FOOTER;
}
}
}
@Override
public void onSwipe(int position) {
//delete item with transaction from database
if (position < mResults.size()) {
mRealm.beginTransaction();
mResults.get(position).deleteFromRealm();
mRealm.commitTransaction();
notifyItemRemoved(position);
}
resetFilterIfEmpty();
}
private void resetFilterIfEmpty() {
if (mResults.isEmpty() && (mFilterOption == Filter.COMPLETE || mFilterOption == Filter.INCOMPLETE)) {
mResetListener.onReset();
}
}
public void markComplete(int position) {
//checking that item is not a footer
if (position < mResults.size()) {
mRealm.beginTransaction();
mResults.get(position).setCompleted(true);
mRealm.commitTransaction();
notifyItemChanged(position);
}
}
public static class DropHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView mTextWhat;
TextView mTextWhen;
MarkListener mMarkListener;
Context mContext;
View mItemView;
TextView mTimer;
//timer
Handler handler;
public long timeRemaining;
public Drop drop;
public DropHolder(View itemView, MarkListener listener) {
super(itemView);
mItemView = itemView;
mContext = itemView.getContext();
itemView.setOnClickListener(this);
mTextWhat = (TextView) itemView.findViewById(R.id.tv_what);
mTextWhen = (TextView) itemView.findViewById(R.id.tv_when);
mTimer = (TextView) itemView.findViewById(R.id.tv_timer);
mMarkListener = listener;
}
public void setWhat(String what) {
mTextWhat.setText(what);
}
public Drop getDrop(Drop drop) {
return drop;
}
public void setTimer(long timer) {
handler = new Handler();
timeRemaining = timer * 1000;
final Runnable runnable = new Runnable() {
@Override
public void run() {
timeRemaining = timeRemaining - 1000;
if (timeRemaining > 0) {
handler.postDelayed(this, 1000);
timeRemaining = timeRemaining / 1000;
mTimer.setText(Long.toString(timeRemaining));
timeRemaining = timeRemaining * 1000;
}
if (timeRemaining == 0) {
mTimer.setText("Czas na lek !");
}
}
};
//kickstart
handler.postDelayed(runnable, 1000);
}
@Override
public void onClick(View v) {
mMarkListener.onMark(getAdapterPosition());
}
public void setBackground(boolean completed) {
Drawable drawable;
if (completed) {
drawable = ContextCompat.getDrawable(mContext, R.color.colorLightBlueAfterClick);
} else {
drawable = ContextCompat.getDrawable(mContext, R.drawable.bg_row_drop);
}
/*if(Build.VERSION.SDK_INT > 15){
mItemView.setBackground(drawable);
} else{
mItemView.setBackgroundDrawable(drawable);
}*/
Util.setBackground(mItemView, drawable);
}
public void setWhen(long when) {
mTextWhen.setText(DateUtils.getRelativeTimeSpanString(when, System.currentTimeMillis(), DateUtils.DAY_IN_MILLIS, 0));
}
}
public static class NoItemsHolder extends RecyclerView.ViewHolder {
public NoItemsHolder(View itemView) {
super(itemView);
}
}
public class FooterHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
Button mBtnAdd;
public FooterHolder(View itemView) {
super(itemView);
mBtnAdd = (Button) itemView.findViewById(R.id.btn_footer);
mBtnAdd.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//were using from this place AddListener
mAddListener.add();
}
}
}
不用保存倒計時時間,而是保存結束日期時間(現在的日期時間+倒數),並在此基礎上進行邏輯運算。 這樣,當應用程序重置或視圖重置時,通過將現在的日期時間與結束日期時間進行比較,倒數計時邏輯將從上次停止的地方繼續。
此外,您發布的代碼正在為每個視圖每秒發布一個Runnable
,即使對於用戶不可見的視圖也是如此。 這會導致應用程序性能下降。 而是創建一個計時器,該計時器可能由托管RecyclerView.Adapter
的Activity
進行控制,它將調用RecyclerView.Adapter.notifyDataSetChanged()
,后者將依次調用RecyclerView.Adapter.onBindViewHolder()
來更新UI。 因此,適配器將更新所有可見的UI元素,這意味着倒數UI(當然也只有可見的UI)也將每秒更新一次。 即使在滾動時,也會調用RecyclerView.Adapter.onBindViewHolder()
來處理。 當數據集很大時,這將大大提高應用程序的性能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.