我已经在我的Android应用中使用Service实现了多个倒数计时器。 CountDownTimer与服务一起运行,因此使用BroadcastReceiver传递数据到片段。
我想将每个计时器作为单独的项目添加到片段中的RecyclerView,并且能够在计时器正在滴答时更新它并控制它 - 暂停,恢复,添加1分钟并删除。 / strong>
目前问题是计时器正在运行的每一秒,新项目被添加到RecyclerView 并且我无法控制它 - 暂停,恢复等等。
服务类:
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(Constants.ACTION.START_FOREGROUND_ACTION)){
HandlerThread thread = new HandlerThread("ServiceStartArguments",
android.os.Process.THREAD_PRIORITY_BACKGROUND);
thread.setName(nameOfFood);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
Thread.currentThread().setName(nameOfFood);
try {
showCountDownTimer(enteredTimeFormatted);
} catch (Exception e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
stopSelf(msg.arg1);
}
private void showCountDownTimer(long number) {
String normalStartTime = String.format(
"%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(number),
TimeUnit.MILLISECONDS.toMinutes(number) -
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(number)),
TimeUnit.MILLISECONDS.toSeconds(number) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(number)));
Intent timerStartInfoIntent = new Intent(TIMER_START_INFO);
timerStartInfoIntent.putExtra("VALUE", normalStartTime);
timerStartInfoIntent.putExtra("NAME_FOOD", nameOfFood);
LocalBroadcastManager.getInstance(NotificationService.this).sendBroadcast(timerStartInfoIntent);
CountDownTimer timer = new CountDownTimer(number, 1000) {
@Override
public void onTick(long millisUntilFinished) {
timeLeft = millisUntilFinished;
counter = millisUntilFinished / 1000;
normalTime = String.format(
"%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(timeLeft),
TimeUnit.MILLISECONDS.toMinutes(timeLeft) -
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(timeLeft)),
TimeUnit.MILLISECONDS.toSeconds(timeLeft) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeLeft)));
Intent timerInfoIntent = new Intent(TIME_INFO);
timerInfoIntent.putExtra("VALUE", normalTime);
timerInfoIntent.putExtra("NAME_FOOD", nameOfFood);
LocalBroadcastManager.getInstance(NotificationService.this).sendBroadcast(timerInfoIntent);
}
@Override
public void onFinish() {
counter = 0;
Intent timerFinishInfoIntent = new Intent(TIMER_FINISH_INFO);
LocalBroadcastManager.getInstance(NotificationService.this).sendBroadcast(timerFinishInfoIntent);
}
};
timer.start();
}
适配器类:
public class TimerRecyclerViewAdapter extends RecyclerView.Adapter<TimerRecyclerViewAdapter.MyViewHolder> {
final private Context mContext;
public List<ModelTimer> mModelTimerList;
private final List<MyViewHolder> listHolder;
public TimerRecyclerViewAdapter(List<ModelTimer> modelTimerList, Context context) {
super();
this.mContext = context;
this.mModelTimerList = modelTimerList;
listHolder = new ArrayList<>();
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView nameTextView;
public final TextView timerTextView;
public final Button pauseBtn;
public final Button addMinBtn;
public final Button deleteBtn;
ModelTimer mModelTimer;
public MyViewHolder(View itemView) {
super(itemView);
nameTextView = (TextView) itemView.findViewById(R.id.active_timer_name);
timerTextView = (TextView) itemView.findViewById(R.id.active_timer_timeLeft);
pauseBtn = (Button) itemView.findViewById(R.id.active_timer_btn_pause);
pauseBtn.setOnClickListener(this);
addMinBtn = (Button) itemView.findViewById(R.id.active_timer_btn_addMin);
addMinBtn.setOnClickListener(this);
deleteBtn = (Button) itemView.findViewById(R.id.active_timer_btn_delete);
deleteBtn.setOnClickListener(this);
}
public void setData (ModelTimer modelTimer){
this.mModelTimer = modelTimer;
timerTextView.setText(modelTimer.expirationTime);
nameTextView.setText(modelTimer.name);
}
@Override
public void onClick(View v) {
// TODO
}
}
@Override
public TimerRecyclerViewAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (parent instanceof RecyclerView) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_active_timer,
parent,
false);
v.setFocusable(true);
return new MyViewHolder(v);
} else {
throw new RuntimeException("No bound to RecyclerViewSelection");
}
}
@Override
public void onBindViewHolder(TimerRecyclerViewAdapter.MyViewHolder holder, int position) {
holder.setData(mModelTimerList.get(position));
synchronized (listHolder){
listHolder.add(holder);
}
}
@Override
public int getItemCount() {
return mModelTimerList.size();
}
在这里,我尝试创建一种方法,每次在特定位置升级计时器,而不是每次定时器滴答时将新项目添加到RecyclerView。
public void swap(List<ModelTimer> modelTimerList){
mModelTimerList.clear();
mModelTimerList.addAll(modelTimerList);
notifyItemChanged(???);
}
public void delete() {
mModelTimerList.clear();
notifyDataSetChanged();
}
}
使用RecyclerView进行分段:
public class ActiveTimersFragment extends Fragment {
private RecyclerView mRecyclerView;
private TimerRecyclerViewAdapter mAdapter;
private ArrayList<ModelTimer> listOfTimers;
private TimerStatusReceiver mTimerStatusReceiver;
private static final String ARG_SECTION_NUMBER = "section_number";
public ActiveTimersFragment() {
}
public static ActiveTimersFragment newInstance(int sectionNumber) {
ActiveTimersFragment activeTimersFragment = new ActiveTimersFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
activeTimersFragment.setArguments(args);
return activeTimersFragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_active_timers, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.fragment_active_timers_recycler_view);
mTimerStatusReceiver = new TimerStatusReceiver();
listOfTimers = new ArrayList<>();
return view;
}
@Override
public void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mTimerStatusReceiver, new IntentFilter(NotificationService.TIME_INFO));
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mTimerStatusReceiver, new IntentFilter(NotificationService.TIMER_START_INFO));
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mTimerStatusReceiver, new IntentFilter(NotificationService.TIMER_FINISH_INFO));
}
@Override
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mTimerStatusReceiver);
}
private class TimerStatusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction().equals(NotificationService.TIME_INFO)) {
ModelTimer modelTimer = new ModelTimer();
if (intent.hasExtra("VALUE")) {
modelTimer.setexpirationTime(intent.getStringExtra("VALUE"));
}
if (intent.hasExtra("NAME_FOOD")) {
modelTimer.setName(intent.getStringExtra("NAME_FOOD"));
}
listOfTimers.add(modelTimer);
mAdapter = new TimerRecyclerViewAdapter(listOfTimers, getActivity());
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// Not working
// mAdapter.swap(listOfTimers);
mRecyclerView.setAdapter(mAdapter);
}
if (intent != null && intent.getAction().equals(NotificationService.TIMER_FINISH_INFO)) {
mAdapter.delete();
}
}
}
}
答案 0 :(得分:1)
您对recyclelerview适配器的整个实现是错误的。在onBindViewHolder()中,您要添加新项目。当RecyclerView尝试显示新项时,将调用onBindViewHolder。因此,如果在onBindViewHolder中添加新项目,它会继续迭代。此外,您应该使用onBindViewHolder在ViewHolder类中设置视图值。检查整个适配器实现。
public class TimerRecyclerViewAdapter extends RecyclerView.Adapter<TimerRecyclerViewAdapter.MyViewHolder> {
final private Context mContext;
public List<ModelTimer> mModelTimerList;
public TimerRecyclerViewAdapter(List<ModelTimer> modelTimerList, Context context) {
super();
this.mContext = context;
this.mModelTimerList = modelTimerList;
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView nameTextView;
public final TextView timerTextView;
public final Button pauseBtn;
public final Button addMinBtn;
public final Button deleteBtn;
public MyViewHolder(View itemView) {
super(itemView);
nameTextView = (TextView) itemView.findViewById(R.id.active_timer_name);
timerTextView = (TextView) itemView.findViewById(R.id.active_timer_timeLeft);
pauseBtn = (Button) itemView.findViewById(R.id.active_timer_btn_pause);
pauseBtn.setOnClickListener(this);
addMinBtn = (Button) itemView.findViewById(R.id.active_timer_btn_addMin);
addMinBtn.setOnClickListener(this);
deleteBtn = (Button) itemView.findViewById(R.id.active_timer_btn_delete);
deleteBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// TODO
}
}
@Override
public TimerRecyclerViewAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (parent instanceof RecyclerView) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_active_timer,
parent,
false);
v.setFocusable(true);
return new MyViewHolder(v);
} else {
throw new RuntimeException("No bound to RecyclerViewSelection");
}
}
@Override
public void onBindViewHolder(TimerRecyclerViewAdapter.MyViewHolder holder, int position) {
ModelTimer modelTimer=mModelTimerList.get(position);
holder.timerTextView.setText(modelTimer.expirationTime);
holder.nameTextView.setText(modelTimer.name);
}
@Override
public int getItemCount() {
return mModelTimerList.size();
}