1

Я внедрил в свое приложение Android несколько таймеров обратного отсчета с сервисом. CountDownTimer работает с сервисом, поэтому данные для фрагмента передаются с помощью BroadcastReceiver.Обновление и управление несколькими CountDownTimer в RecyclerView (пауза, резюме, удаление)

Я хотел бы добавить каждый таймер в отдельный фрагмент в RecyclerView во фрагменте и иметь возможность обновлять его по мере того, как таймер тикает, а также управлять им - приостанавливать, возобновлять, добавлять 1 мин и удалять.

На данный момент проблема в том, чтокаждый второй, что таймер работает, новый элемент добавляется в 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(); 
     } 

    } 
} 
} 

ответ

1

Вся ваша реализация recyclerview адаптер неправильно. В onBindViewHolder() вы добавляете новый элемент. onBindViewHolder вызывается, когда RecyclerView пытается показать новый элемент. Таким образом, он продолжает итерацию, если вы добавите новый элемент в 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(); 
    } 
Смежные вопросы