It is necessary to write an application in which the elements are placed in RecyclerView . Each item has a start and stop button for CountDownTimer , which updates the time status of each item in the list. The problem is that if you scroll through the list and then switch to another activity, then when you return to the activity with the RecyclerView line containing the time disappears, and the timer reaches the end in the background and then starts to signal. Buttons lose touch with the spawned thread and cannot stop the timer. Can anyone have an example of writing a similar RecyclerView ?

 private class ScooterHolder extends RecyclerView.ViewHolder implements View.OnClickListener,TextToSpeech.OnInitListener { private Scooter mScooter; private TextView mTitleTextView,mDateTextView, mTextViewTarif,mTextViewStatus,mTextViewSum; private ToggleButton mToggleButtonStart,mToggleButtonPaid; private RelativeLayout mRelativeLayout; private EditText mEditTextTime; private CountDownTimer timer; private Timer mTimer; private MyTimerTask mMyTimerTask; public ScooterHolder(View itemView) { super(itemView); itemView.setOnClickListener(this); mTitleTextView = (TextView) itemView.findViewById(R.id.list_item_scooter_title_text_view); mDateTextView = (TextView) itemView.findViewById(R.id.list_item_scooter_date_text_view); mTextViewTarif=(TextView)itemView.findViewById(R.id.list_item_scooter_tarif_text_view); mTextViewStatus=(TextView)itemView.findViewById(R.id.list_item_scooter_status_text_view); mTextViewSum=(TextView)itemView.findViewById(R.id.list_item_scooter_sum_text_view); mToggleButtonStart=(ToggleButton) itemView.findViewById(R.id.list_item_scooter_start_toggle_button); mToggleButtonPaid=(ToggleButton)itemView.findViewById(R.id.list_item_scooter_paid_toggle_button); mRelativeLayout=(RelativeLayout)itemView.findViewById(R.id.list_item_layout); mEditTextTime=(EditText)itemView.findViewById(R.id.list_item_scooter_edit_text_time); mToggleButtonStart.setOnClickListener(this); mToggleButtonPaid.setOnClickListener(this); mTitleTextView.setOnClickListener(this); mTTS = new TextToSpeech(getActivity(), this); } public void bindScooter(Scooter scooter) { mScooter = scooter; mTitleTextView.setText("Скутер №"+mScooter.getTitle()); mTextViewTarif.setText("Тариф: "+mScooter.getTarif()); mTextViewStatus.setText("Статус скутера: "+mScooter.getStatus()); mEditTextTime.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { int result = actionId & EditorInfo.IME_MASK_ACTION; switch (result) { case EditorInfo.IME_ACTION_DONE: mScooter.setDate((Long.valueOf(v.getText().toString())*60*1000)); mTextViewSum.setText("Сумма к оплате: "+((Double.valueOf(v.getText().toString()))*mScooter.getSum())+" руб."); mEditTextTime.setText(v.getText().toString()+" мин"); ScooterLab.get(getActivity()).updateScooter(mScooter); InputMethodManager imm=(InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); break; } return true; } }); if (mScooter.isPaid()==true){ mToggleButtonPaid.setTextColor(Color.GREEN); mToggleButtonPaid.setChecked(true); }else { mToggleButtonPaid.setTextColor(Color.RED); } if (mScooter.isStart()==true){ mToggleButtonStart.setTextColor(Color.RED); mToggleButtonStart.setChecked(true); }else { mToggleButtonStart.setTextColor(Color.GREEN); } if (mScooter.getStatus().equals("Свободен")){ mRelativeLayout.setBackgroundColor(getResources().getColor(R.color.color_free)); mToggleButtonStart.setEnabled(true); mToggleButtonPaid.setEnabled(true); }else if(mScooter.getStatus().equals("Работает")){ mRelativeLayout.setBackgroundColor(Color.YELLOW); mToggleButtonStart.setEnabled(true); mToggleButtonPaid.setEnabled(true); }else { mRelativeLayout.setBackgroundColor(getResources().getColor(R.color.color_charging)); mToggleButtonStart.setEnabled(false); mToggleButtonPaid.setEnabled(false); } } @Override public void onClick(View v) { switch (v.getId()){ case R.id.list_item_scooter_title_text_view: Intent intent=ScooterActivity.newIntent(getActivity(),mScooter.getId()); startActivity(intent); break; case R.id.list_item_scooter_paid_toggle_button: if (mToggleButtonPaid.isChecked()==true){ mToggleButtonPaid.setTextColor(Color.GREEN); mScooter.setPaid(true); }else { mToggleButtonPaid.setTextColor(Color.RED); mScooter.setPaid(false); } break; case R.id.list_item_scooter_start_toggle_button: if (mToggleButtonStart.isChecked()==true){ mToggleButtonStart.setTextColor(Color.RED); mRelativeLayout.setBackgroundColor(Color.YELLOW); mScooter.setStart(true); mScooter.setStatus("Работает"); mTextViewStatus.setText("Статус скутера: "+mScooter.getStatus()); showTimer(10000); }else { mToggleButtonStart.setTextColor(Color.GREEN); mRelativeLayout.setBackgroundColor(getResources().getColor(R.color.color_free)); mScooter.setStart(false); mScooter.setStatus("Свободен"); mTextViewStatus.setText("Статус скутера: "+mScooter.getStatus()); mScooter.setDate(0); //timerStart(2); if(mTimer!=null){ timerStart(2); mTimer=null; } if(timer!=null){ timer.cancel(); timer=null; } } break; } ScooterLab.get(getActivity()).updateScooter(mScooter); } //таймер отсчета времени public void showTimer(long countdownMillis) { if(timer != null) { timer.cancel(); } timer = new CountDownTimer(countdownMillis, 1000) { @Override public void onTick(long millisUntilFinished) { mDateTextView.setText("Осталось "+String.format("%d мин %d сек", TimeUnit.MILLISECONDS.toMinutes( millisUntilFinished), TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)))); mScooter.setDate(millisUntilFinished); ScooterLab.get(getActivity()).updateScooter(mScooter); } @Override public void onFinish() { mDateTextView.setText("Время вышло!"); String text = "Скутер №"+mScooter.getTitle()+" завершил работу"; mTTS.speak(text, TextToSpeech.QUEUE_FLUSH, null); timerStart(1); } }.start(); } //таймер для повторного воспроизведения озвучки private void timerStart(int i) { if(mTimer != null) { mTimer.cancel(); } if (i == 1) { mTimer = new Timer(); mMyTimerTask = new MyTimerTask(); // delay 1000ms, repeat in 5000ms mTimer.schedule(mMyTimerTask, 1000, 5000); } else { mTimer.cancel(); } } class MyTimerTask extends TimerTask { @Override public void run() { try { getActivity().runOnUiThread(new Runnable() { @Override public void run() { String text = "Скутер №" + mScooter.getTitle() + " завершил работу"; Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show(); mTTS.speak(text, TextToSpeech.QUEUE_FLUSH, null); } }); }catch (Exception e){ e.printStackTrace(); } } } //озвучка @Override public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { Locale locale = new Locale("ru"); int result = mTTS.setLanguage(locale); if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { Log.e("TTS", "Извините, этот язык не поддерживается"); } } else { Log.e("TTS", "Ошибка!"); } } } private class ScooterAdapter extends RecyclerView.Adapter<ScooterHolder> { private List<Scooter> mScooters; public ScooterAdapter(List<Scooter> scooters) { mScooters = scooters; } @Override public ScooterHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater layoutInflater = LayoutInflater.from(getActivity()); View view = layoutInflater.inflate(R.layout.list_item_scooter, parent, false); return new ScooterHolder(view); } @Override public void onBindViewHolder(ScooterHolder holder, int position) { Scooter scooter = mScooters.get(position); holder.bindScooter(scooter); } @Override public int getItemCount() { return mScooters.size(); } public void setScooters(List<Scooter> scooters) { mScooters= scooters; } } 
  • Nobody has an example. The problem is in your code. On that line. No, not the one, but the next one. Is it clear? - Vladyslav Matviienko
  • So far, on your question, you can say that you probably should at least use the service if you want your application to work regardless of the activity - Vladyslav Matviienko

2 answers 2

The problem was in the OnResume() method in which the adapter was updated. The entire list was updated when the item was changed, rewritten to update a specific position and everything began to work.

    It seems to me that the timer data should not be stored in the element, but in an array. For example, there is a certain array of times by the number of positions.

     long[] times = new long[*количество*]; //можно использовать гибкий ArrayList 

    When creating an item, we simply write the time we need into it -

     times[position] = new Date().getTime(); 

    In the element itself, in the getView () method, your "counter" simply calculates and displays the time, in the format you need, from the one stored in the array. showTimer (times [position]);

    Thus, the data will always be correct.