kostyaBoss kostyaBoss - 3 years ago 39
Android Question

multiple countdowntimers recycler view

I have a problem with multiple countdown timers and recycle view. When i add new timer, previous one stops. And then it works very strange, when the seconds are same, many timers can work in one time. I've searched a lot but didn't find solution to my problem. Help me please

My holder class

public class MyViewHolder extends RecyclerView.ViewHolder{

private long timeCountInMilliSeconds = 1 * 60000;

private enum TimerStatus {
STARTED,
STOPPED
}

public TextView title;
private TimerStatus timerStatus = TimerStatus.STOPPED;
private ProgressBar progressBarCV;
public TextView textViewTimeCV;
private CountDownTimer countDownTimer;
private Handler handler;

public MyViewHolder(View view) {
super(view);

initViews(view);
}

private void initViews(View view) {
title = (TextView) view.findViewById(R.id.title);
progressBarCV = (ProgressBar) view.findViewById(R.id.progressBarCV);
textViewTimeCV = (TextView) view.findViewById(R.id.textViewTimeCV);
}

public void startStop(String minutes) {
if (timerStatus == TimerStatus.STOPPED) {


// call to initialize the timer values
setTimerValues(minutes);
// call to initialize the progress bar values
setProgressBarValues();
// changing the timer status to started
timerStatus = TimerStatus.STARTED;
// call to start the count down timer
startCountDownTimer();

} else {

// changing the timer status to stopped
timerStatus = TimerStatus.STOPPED;
stopCountDownTimer();
}
}

private void setTimerValues(String minutes) {
int time = 0;
if (!minutes.isEmpty() || Integer.parseInt(minutes) != 0) {

time = Integer.parseInt(minutes);
}

// assigning values after converting to milliseconds
timeCountInMilliSeconds = time * 60 * 1000;
}

private void startCountDownTimer() {
handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
countDownTimer = new CountDownTimer(timeCountInMilliSeconds, 1000) {
@Override
public void onTick(long millisUntilFinished) {

textViewTimeCV.setText(hmsTimeFormatter(millisUntilFinished));

progressBarCV.setProgress((int) (millisUntilFinished / 1000));


}

@Override
public void onFinish() {

textViewTimeCV.setText(hmsTimeFormatter(timeCountInMilliSeconds));
// call to initialize the progress bar values
setProgressBarValues();
// changing the timer status to stopped
timerStatus = TimerStatus.STOPPED;
}

}.start();
}
}, 1000);


}

private void stopCountDownTimer() {
countDownTimer.cancel();
}

private void setProgressBarValues() {

progressBarCV.setMax((int) timeCountInMilliSeconds / 1000);
progressBarCV.setProgress((int) timeCountInMilliSeconds / 1000);
}

private String hmsTimeFormatter(long milliSeconds) {

String hms = String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(milliSeconds),
TimeUnit.MILLISECONDS.toMinutes(milliSeconds) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(milliSeconds)),
TimeUnit.MILLISECONDS.toSeconds(milliSeconds) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliSeconds)));

return hms;
}
}


Model class

public class Task {
private String title;
private String time;

public Task() {
}

public Task(String title, String description, String time) {
this.title = title;
this.time = time;
}

public String getTitle() {
return title;
}

public void setTitle(String name) {
this.title = name;
}

public String getTime() {
return time;
}

public void setTime(String time) {
this.time = time;
}
}


Adapter class

public class TaskAdapter extends RecyclerView.Adapter<MyViewHolder> {

private List<Task> taskList;

public TaskAdapter(List<Task> taskList) {
this.taskList = taskList;
}



@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cardview_layout, parent, false);

return new MyViewHolder(itemView);
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {

Task task = taskList.get(position);
holder.title.setText(task.getTitle());
holder.textViewTimeCV.setText(task.getTime());
holder.startStop(task.getTime());
}


@Override
public int getItemCount() {
return taskList.size();
}

}


And finally my activity class

public class MainActivity extends AppCompatActivity {

Task task;

private FloatingNavigationView mFloatingNavigationView;

public List<Task> taskList = new ArrayList<>();
private RecyclerView recyclerView;
public TaskAdapter tAdapter;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
/*startActivity(new Intent(MainActivity.this, SecondActivity.class));*/
// just some data to make a timer
prepareTaskData("jakldsj","asasd" , String.valueOf(1));
}
});

recyclerView = (RecyclerView) findViewById(R.id.recycler_view);

tAdapter = new TaskAdapter(taskList);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setAdapter(tAdapter);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();

//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}

return super.onOptionsItemSelected(item);
}
private void prepareTaskData(String title, String description, String time) {

method to set the values into the list
task = new Task(title, description, time);
taskList.add(task);
tAdapter.notifyDataSetChanged();
}

}

Answer Source

I've spent some days and finally found the solution. The mistake was in notifyDataChanged()method in activity. Recycler view, using this method reuses cards, that's the reason, why timers where stopping (when card is recycling, all processes are stopped, and in startStop() method of Holder class we were simply heding in "else" case). In prepareTaskData() simply change last string on tAdapter.notifyItemChanged(taskList.size()-1);

Hope, this will be useful for someone

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download