我已经在应用程序上工作了很长时间。这个应用程序应该采用姓氏并测量访问时间,这是恒定的(30分钟)。我有一个Family对象,其中包含名称,成员数和访问结束等信息,表示为未来的毫秒值。
我实现定时器部分的方法只是创建一个名为CountDownManager的类,它负责更新和计算列出的所有系列视图持有者的剩余时间。
问题是,如果我清理我的数据(持有者和数据集)并添加一个新系列,则该系列不会添加到CountDownTimer类中。
以下是正确添加家庭时的图像:
以下是我的适配器,我的视图持有者和我的CoundDownManager类的代码:
package bikurim.silverfix.com.bikurim.adapters;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filterable;
import android.widget.Toast;
import java.util.ArrayList;
import bikurim.silverfix.com.bikurim.Constants;
import bikurim.silverfix.com.bikurim.adapters.holders.FamilyViewHolder;
import bikurim.silverfix.com.bikurim.adapters.holders.GenericViewHolder;
import bikurim.silverfix.com.bikurim.adapters.holders.TimeUpViewHolder;
import bikurim.silverfix.com.bikurim.models.Family;
import bikurim.silverfix.com.bikurim.R;
import bikurim.silverfix.com.bikurim.utils.managers.MediaPlayerManager;
import bikurim.silverfix.com.bikurim.utils.Utils;
import bikurim.silverfix.com.bikurim.utils.interfaces.HolderListener;
import bikurim.silverfix.com.bikurim.utils.managers.CountDownManager;
import bikurim.silverfix.com.bikurim.utils.interfaces.EventListener;
public class FamiliesAdapter extends GenericAdapter implements Filterable, EventListener, HolderListener {
// last position holds the last position of the element that was added, for animation purposes
private static int lastPosition = -1;
private int[] viewTypes;
private ItemTouchHelper touchHelper;
private CountDownManager countDownManager;
public FamiliesAdapter(Context context, ArrayList<Family> families, ItemTouchHelper touchHelper) {
super(context, families);
this.touchHelper = touchHelper;
viewTypes = Constants.Tags.VIEW_TYPES;
countDownManager = new CountDownManager(Constants.Values.TIME_INTERVAL, this);
countDownManager.start();
}
@Override
public GenericViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Inflating the view from a given layout resource file
Log.d("A function has called", "onCreateViewHolder() was invoked");
View v;
switch (viewType) {
case Constants.Tags.FAMILY_VIEW:
v = LayoutInflater.from(context).inflate(R.layout.family_list_item, parent, false);
FamilyViewHolder fvh = new FamilyViewHolder(context, v);
return fvh;
case Constants.Tags.TIME_UP_VIEW:
v = LayoutInflater.from(context).inflate(R.layout.timeup_list_item, parent, false);
TimeUpViewHolder tvh = new TimeUpViewHolder(context, v, this);
return tvh;
}
return null;
}
@Override
public void onBindViewHolder(GenericViewHolder holder, int position) {
// Binds the Family object to the holder view
Family family = families.get(position);
holder.bindData(family);
Log.d("A function has called", "onBindViewHolder() was invoked, IS FAMILY ADDED: " + ((FamilyViewHolder) holder).isHolderAdded);
if(holder instanceof FamilyViewHolder){
if(!((FamilyViewHolder) holder).isHolderAdded) {
countDownManager.addHolder((FamilyViewHolder) holder);
((FamilyViewHolder) holder).isHolderAdded = true;
}
}
// Sets animation on the given view, in case it wasn't displayed before
Utils.setSlideAnimation(context, holder.getView(), position, lastPosition, false);
}
@Override
public int getItemViewType(int position) {
if(families.get(position).whenInMillis <= System.currentTimeMillis())
return viewTypes[1];
return viewTypes[0];
}
/* Changes the UI of a holder to a time's up view with a flickering ImageButton and a TextView*/
@Override
public void onFinish(FamilyViewHolder holder) {
// Resets the holder for future uses
holder.reset();
// Play a sound for notifying purposes
MediaPlayerManager.playSound(MediaPlayerManager.Sound.END);
// Vibrates the device for 1.5 seconds
Utils.vibrate(context, Constants.Values.VIBRATION_LENGTH_SHORT);
notifyItemChanged(holder.getAdapterPosition());
}
@Override
public void onLessThanMinute(FamilyViewHolder holder) {
// if the sound option is on, play a swoosh sound
MediaPlayerManager.playSound(MediaPlayerManager.Sound.ALERT);
Drawable stroke = ContextCompat.getDrawable(context, R.drawable.family_item_red_stroke);
holder.frame.setBackground(stroke);
Utils.setFadeAnimation(holder.frame);
holder.isStrokeChanged = true;
}
@Override
public void onRemoveTimeUpViewHolder(int pos, GenericViewHolder holder) {
touchHelper.startSwipe(holder);
removeData(pos, holder);
}
public void removeData(int pos, GenericViewHolder holder) {
// Sets the last position to the given deleted position for animation purposes
lastPosition = pos;
// Removes the family object from the data set
String name = Utils.getLastName(families.get(pos).name);
families.remove(pos);
notifyItemRemoved(pos);
notifyItemRangeChanged(pos, getItemCount());
if(holder instanceof FamilyViewHolder)
// Cancels the the timer and removes it from the entry set
countDownManager.removeHolder((FamilyViewHolder) holder);
holder.reset();
Toast.makeText(context, "משפחת "+name+" נמחקה מהרשימה", Toast.LENGTH_SHORT).show();
}
/* Cancels the timers and clears the entry set */
public void cancelTimers() {
countDownManager.reset();
countDownManager.clear();
countDownManager.stop();
}
/* Clears the adapter's data and resets the last position to -1 */
@Override
public void clearData() {
super.clearData();
cancelTimers();
lastPosition = -1;
}
}
FamilyViewHolder:
package bikurim.silverfix.com.bikurim.adapters.holders;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.CardView;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import bikurim.silverfix.com.bikurim.R;
import bikurim.silverfix.com.bikurim.models.Family;
import bikurim.silverfix.com.bikurim.utils.Utils;
/**
* Created by David on 07/07/2016.
*
* The official view holder of the adapter. Holds references to the relevant views inside the layout
*/
public class FamilyViewHolder extends GenericViewHolder {
public boolean isStrokeChanged, isHolderAdded;
public CardView cardView;
public RelativeLayout frame;
public TextView name;
public TextView timeLeft;
public TextView visitors;
public Family family;
private ColorStateList colorStateList;
public FamilyViewHolder(Context context, View v) {
super(v, context);
// isStrokeChanged represents whether the holder is under 60 seconds or not
isStrokeChanged = false;
isHolderAdded = false;
// Getting the references for the UI components
cardView = (CardView) v.findViewById(R.id.cv);
frame = (RelativeLayout) v.findViewById(R.id.card_frame);
name = (TextView) v.findViewById(R.id.person_Lname);
visitors = (TextView) v.findViewById(R.id.visitors);
timeLeft = (TextView) v.findViewById(R.id.person_timeLeft);
// Sets a reference to the old colors of the text view
colorStateList = timeLeft.getTextColors();
}
@Override
public void bindData(Family family) {
this.family = family;
name.setText(Utils.formatNameString(family.name));
visitors.setText(" מבקרים: "+family.visitorsNum);
}
@Override
public void reset() {
family = null;
name.setText("");
visitors.setText("");
timeLeft.setText("");
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.family_item_blue_stroke);
this.frame.clearAnimation();
this.frame.setAnimation(null);
this.frame.setBackground(drawable);
isStrokeChanged = false;
isHolderAdded = false;
}
public ColorStateList getOriginalColors() {
return colorStateList;
}
}
CountDownManager:
package bikurim.silverfix.com.bikurim.utils.managers;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import bikurim.silverfix.com.bikurim.Constants;
import bikurim.silverfix.com.bikurim.adapters.holders.FamilyViewHolder;
import bikurim.silverfix.com.bikurim.utils.interfaces.EventListener;
import bikurim.silverfix.com.bikurim.utils.Utils;
/**
* Created by David on 07/07/2016.
* @author David
* Inspired by MiguelLavigne
*
* A custom CountDownTimer class, which takes care of all the running timers
*/
public class CountDownManager {
private final long interval;
private long base;
// Holds references for all the visible text views
private ArrayList<FamilyViewHolder> holders;
private EventListener listener;
public CountDownManager(long interval, EventListener listener) {
this.listener = listener;
this.interval = interval;
holders = new ArrayList<>();
}
public void start() {
base = System.currentTimeMillis();
handler.sendMessage(handler.obtainMessage(MSG));
}
public void stop() {
handler.removeMessages(MSG);
}
public void reset() {
synchronized (this) {
base = System.currentTimeMillis();
}
}
public void addHolder(FamilyViewHolder holder) {
synchronized (holders) {
holders.add(holder);
}
}
public void removeHolder(FamilyViewHolder holder) {
synchronized (holders) {
holders.remove(holder);
}
}
private void onTick(long elapsedTime) {
try {
if(!holders.isEmpty()) {
long timeLeft, lengthOfVisit;
for (FamilyViewHolder holder : holders) {
lengthOfVisit = holder.family.whenInMillis - base;
timeLeft = lengthOfVisit - elapsedTime;
if(timeLeft > 0) {
if(timeLeft <= Constants.Values.ALERT_TIME && !holder.isStrokeChanged) {
listener.onLessThanMinute(holder);
}
holder.family.timeLeft = timeLeft;
holder.timeLeft.setText(Utils.updateFormatTime(timeLeft));
} else {
listener.onFinish(holder);
removeHolder(holder);
}
}
Log.d("Holder length:", "" + holders.size());
}
} catch (ConcurrentModificationException e) {
Log.d("Concurrent Error", "App will shut down now");
e.printStackTrace();
}
}
public void clear() {
synchronized (holders) {
for(FamilyViewHolder holder : holders)
holder.reset();
holders.clear();
}
}
private static final int MSG = 1;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
synchronized (CountDownManager.this) {
long elapsedTime = System.currentTimeMillis() - base;
onTick(elapsedTime);
sendMessageDelayed(obtainMessage(MSG), interval);
}
}
};
}
有什么问题?