Использование CountDownTimers в RecyclerView и методах

У меня есть вопрос о нескольких таймерах в представлении ресайклера. На данный момент у меня есть функциональный rv, но я застрял на переопределении методов onStop, onPause, onResume. Я хочу, чтобы мое приложение продолжало обратный отсчет, пока оно закрыто. Пожалуйста, помогите мне найти решение, я немного новичок в Android.

Мой код:

Класс держателя

public class MyViewHolder extends RecyclerView.ViewHolder {

private long timeCountInMilliSeconds = 1 * 60000;

public long timeLeft = 0;

private enum TimerStatus {
    STARTED,
    STOPPED
}

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

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() {
    countDownTimer = new CountDownTimer(timeCountInMilliSeconds, 1000) {
        @Override
        public void onTick(long millisUntilFinished) {

            textViewTimeCV.setText(hmsTimeFormatter(millisUntilFinished));

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

            timeLeft = millisUntilFinished;

            Log.d("timeLeft", String.valueOf(timeLeft));

        }

        @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();
}

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;
}}

Класс модели

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;
}}

Адаптер

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);
    MyViewHolder holder = new MyViewHolder(itemView);
    return holder;
}

@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();
}}

Основное действие (инициализация здесь адаптера и т. д.)

public class MainActivity extends AppCompatActivity {


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


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

    initializeDrawer();

    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));
        }
    });

    recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    recyclerView.setDrawingCacheEnabled(true);
    recyclerView.setItemViewCacheSize(50);

    tAdapter = new TaskAdapter(taskList);
    RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
    recyclerView.setLayoutManager(mLayoutManager);
    recyclerView.addOnItemTouchListener(new RecyclerViewTouchListener());
    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);
}

@Override
protected void onResume() {
    super.onResume();
    tAdapter.notifyItemChanged(taskList.size()-1);
}

private void initializeDrawer()
{

    AccountHeader headerResult = initializeHeader();

    PrimaryDrawerItem item1 = new PrimaryDrawerItem().withIdentifier(1).withName(R.string.app_name);
    SecondaryDrawerItem item2 = new SecondaryDrawerItem().withIdentifier(2).withName(R.string.slogan_main);
    //create the drawer and remember the `Drawer` result object
    Drawer result = new DrawerBuilder()
            .withActivity(this)
            .withAccountHeader(headerResult)
            //.withToolbar(toolbar)
            .addDrawerItems(
                    item1,
                    new DividerDrawerItem(),
                    item2,
                    new SecondaryDrawerItem().withName(R.string.material_drawer_close)
            )
            .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
                @Override
                public boolean onItemClick(View view, int position, IDrawerItem drawerItem) {
                    // do something with the clicked item :D





                    return true;
                }
            })
            .build();
}
private AccountHeader initializeHeader()
{

    AccountHeader headerResult = new AccountHeaderBuilder()
            .withActivity(this)
            .withHeaderBackground(R.drawable.drawable_circle_dark_blue)
            .addProfiles(
                    new ProfileDrawerItem().withName("Mike Penz").withEmail("[email protected]").withIcon(getResources().getDrawable(R.drawable.drawable_circle_dark_blue))
            )
            .withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() {
                @Override
                public boolean onProfileChanged(View view, IProfile profile, boolean currentProfile) {
                    return false;
                }
            })
            .build();

    return headerResult;}

Второе действие (здесь я устанавливаю значения в свой список, который подключен к моему адаптеру)

public class SecondActivity extends AppCompatActivity implements View.OnClickListener {

Task task;


private EditText editTextMinute;
private ImageView imageViewStartStop;
private EditText editTextTitle;

private String title;
private String minutes;


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

    // method call to initialize the views
    initViews();
    // method call to initialize the listeners
    initListeners();

}

/**
 * method to initialize the views
 */
private void initViews() {
    editTextMinute = (EditText) findViewById(R.id.editTextMinute);
    imageViewStartStop = (ImageView) findViewById(R.id.imageViewStartStop);
    editTextTitle = (EditText) findViewById(R.id.editTextTitle);
}

/**
 * method to initialize the click listeners
 */
private void initListeners() {
    imageViewStartStop.setOnClickListener(this);
}

/**
 * implemented method to listen clicks
 *
 * @param view
 */
@Override
public void onClick(View view) {
    switch (view.getId()) {
        case R.id.imageViewStartStop:
            prepareTaskData(title, null, minutes);

            break;
    }
}


private void prepareTaskData(String title, String description, String time) {

    time = editTextMinute.getText().toString().trim();
    // fetching minutes for Task obj
    minutes = editTextMinute.getText().toString();
    // fetching value from edit text and type cast to string
    title = editTextTitle.getText().toString();
    // toast message to fill edit text
    if(minutes.isEmpty() || minutes == null || minutes == String.valueOf(0) ||  title.isEmpty() )
    {
        Toast.makeText(getApplicationContext(), getString(R.string.message_minutes_or_title), Toast.LENGTH_LONG).show();
    }
    else
    {
        task = new Task(title, description, time);
        taskList.add(task);
        tAdapter.notifyItemChanged(taskList.size() - 1);
        finish();
    }
}}

Может быть, мне следует реализовать класс обслуживания в моем проекте? Любая информация будет очень полезна для меня


person kboskin    schedule 01.08.2017    source источник


Ответы (1)


Вам нужно добавить таймер обратного отсчета в метод onCreateViewHolder RecyclerView, потому что onCreateViewHolder будет вызываться только один раз.

onBindViewHolder будет вызываться каждый раз, когда пользователь прокручивает вверх или вниз

См. это

person Mani    schedule 02.08.2017
comment
Спасибо, мне очень помогло! Но мой вопрос в том, как установить мои таймеры также в фоновом режиме моего приложения. Я провожу несколько дней в поисках, и я нашел решение - использовать класс обслуживания. Но я до сих пор не понимаю, как это реализовать с помощью таймеров ctd в представлении ресайклера. - person kboskin; 03.08.2017
comment
Вам нужен рабочий код для того же? или более подробное объяснение? - person Mani; 03.08.2017
comment
Оба, если можно - person kboskin; 05.08.2017