RecyclerView 목록 카운트다운 실현

최근 에 하나의 프로젝트 를 만 들 려 면 리스트 카운트다운 기능 을 사용 해 야 합 니 다.반나절 을 두 드 려 서 드디어 만 들 었 습 니 다.안 탁 에서 이 효 과 를 실현 하려 면 Countdown timer 를 사용 해 야 합 니 다.이런 사용 을 통 해 카운트다운 효 과 를 실현 할 수 있 을 뿐만 아니 라 카운트다운 과정 에서 두 개의 bug 도 완벽 하 게 해결 할 수 있 습 니 다.
1.메모리 문제
2.recyclerview 의 item 재 활용 으로 항목 별 시간 착란
일단 실현 의 최종 효 과 를 살 펴 보 겠 습 니 다.

목록 을 어떻게 표시 하 는 지 저 는 모두 가 할 것 이 라 고 믿 습 니 다.여기 에는 카운트다운 기능 이 실 현 된 adapter 류 만 첨부 합 니 다.

public class ClockAdapter extends RecyclerView.Adapter<ClockAdapter.ClockViewHolder> {
 private SparseArray<CountDownTimer> countDownMap = new SparseArray<>();

 @Override
 public ClockViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rv, parent, false);

 return new ClockViewHolder(view);
 }
 /**
 *     
 */
 public void cancelAllTimers() {
 if (countDownMap == null) {
  return;
 }
 for (int i = 0,length = countDownMap.size(); i < length; i++) {
  CountDownTimer cdt = countDownMap.get(countDownMap.keyAt(i));
  if (cdt != null) {
  cdt.cancel();
  }
 }
 }

 @Override
 public void onBindViewHolder(final ClockViewHolder holder, int position) {
 long betweenDate;
 if (position == 0) {
  betweenDate= DateUtil.getLeftTime("2017-8-8 12:10:10");
 } else {
  betweenDate= DateUtil.getLeftTime("2017-8-9 15:10:10");
 }

 if (holder.countDownTimer != null) {
  holder.countDownTimer.cancel();
 }

 if (betweenDate > 0) {
  holder.countDownTimer = new CountDownTimer(betweenDate, 1000) {
  public void onTick(long millisUntilFinished) {
   millisUntilFinished = millisUntilFinished / 1000;
   int hours = (int) (millisUntilFinished / (60 * 60));
   int leftSeconds = (int) (millisUntilFinished % (60 * 60));
   int minutes = leftSeconds / 60;
   int seconds = leftSeconds % 60;

   final StringBuffer sBuffer = new StringBuffer();
   sBuffer.append(addZeroPrefix(hours));
   sBuffer.append(":");
   sBuffer.append(addZeroPrefix(minutes));
   sBuffer.append(":");
   sBuffer.append(addZeroPrefix(seconds));
   holder.clock.setText(sBuffer.toString());
  }
  public void onFinish() {
//                
  }
  }.start();
  countDownMap.put(holder.clock.hashCode(), holder.countDownTimer);
 } else {
//               
 }


 }

 @Override
 public int getItemCount() {
 return 25;
 }

 class ClockViewHolder extends RecyclerView.ViewHolder {

 TextView clock;
 CountDownTimer countDownTimer;

 public ClockViewHolder(View itemView) {
  super(itemView);
  clock = (TextView) itemView.findViewById(R.id.clock);
 }
 }
}
그 중에서 cancelAllTimer()방법 은 메모리 문 제 를 해결 합 니 다.이 줄 코드 를 통 해 item 의 hashcode 를 key 로 SparseArray 에 설정 하면 cancelAllTimer 방법 에서 하나씩 꺼 내 카운트다운 취소 작업 을 할 수 있 습 니 다.

countDownMap.put(holder.clock.hashCode(),holder.countDownTimer);
다음 줄 코드 를 통 해 Countdown Timer 클래스 를 새로 만 듭 니 다.

holder.countDownTimer = new CountDownTimer(betweenDate, 1000) {
 public void onTick(long millisUntilFinished) {
 millisUntilFinished = millisUntilFinished / 1000;
 int hours = (int) (millisUntilFinished / (60 * 60));
 int leftSeconds = (int) (millisUntilFinished % (60 * 60));
 int minutes = leftSeconds / 60;
 int seconds = leftSeconds % 60;
 final StringBuffer sBuffer = new StringBuffer();
 sBuffer.append(addZeroPrefix(hours));
 sBuffer.append(":")  sBuffer.append(addZeroPrefix(minutes));
   sBuffer.append(":");
   sBuffer.append(addZeroPrefix(seconds));
   holder.clock.setText(sBuffer.toString());
}
public void onFinish() {
//              
}
}.start();
그것 의 소스 코드 를 분석 하 다.

public CountDownTimer(long millisInFuture, long countDownInterval) {
 mMillisInFuture = millisInFuture;
 mCountdownInterval = countDownInterval;
 }
이 를 통 해 알 수 있 듯 이 두 개의 값 을 설 치 했 는데 첫 번 째 는 카운트다운 종료 시간 이 고 두 번 째 는 갱신 시간의 간격 이다.
그리고 start 방법 으로 시작 하고 start 방법 에서 진행 되 는 처 리 를 살 펴 보 겠 습 니 다.

public synchronized final CountDownTimer start() {
 mCancelled = false;
 if (mMillisInFuture <= 0) {
  onFinish();
  return this;
 }
 mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
 mHandler.sendMessage(mHandler.obtainMessage(MSG));
 return this;
 }
원본 코드 에 서 는 카운트다운 마감 시간 이 0 보다 적 을 때,즉 카운트다운 이 끝 날 때 onFinish 방법 을 사용 합 니 다.만약 시간 이 끝나 지 않 았 다 면 handler 의 비동기 메시지 체 제 를 통 해 메 시 지 를 보 냅 니 다.전체 절 차 를 통 해 최종 방법 은 handler 의 handleMessage 방법 에 들 어 갑 니 다.이 비동기 절 차 를 잘 모 르 는 파트너 가 있다 면,내 가 이전에 쓴 비동기 메시지 메커니즘 의 문장 을 보 러 갈 수 있다android 비동기 메시지 메커니즘,원본 차원 철저히 분석자,다음은 handler 의 handle Message 방법 을 살 펴 보 겠 습 니 다.

private Handler mHandler = new Handler() {

 @Override
 public void handleMessage(Message msg) {

 synchronized (CountDownTimer.this) {
 if (mCancelled) {
  return;
 }

 final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();

 if (millisLeft <= 0) {
  onFinish();
 } else if (millisLeft < mCountdownInterval) {
 // no tick, just delay until done
 sendMessageDelayed(obtainMessage(MSG), millisLeft);
 } else {
long lastTickStart=SystemClock.elapsedRealtime();
  onTick(millisLeft);
 // take into account user's onTick taking time to execute
 long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();

// special case: user's onTick took more than interval to
// complete, skip to next interval
 while (delay < 0) delay += mCountdownInterval;
 sendMessageDelayed(obtainMessage(MSG), delay);
  }
  }
 }
 };
이 소스 코드 는 아직 잘 알 고 있 을 것 이 라 고 믿 습 니 다.먼저 남 은 시간 을 계산 하고 남 은 시간 이 새로 고침 시간 보다 적 으 면 시간 이 끝 날 때 까지 지연 메 시 지 를 보 냅 니 다.남 은 시간 이 새로 고침 시간 보다 많 으 면 onTick(millisLeft)방법 을 호출 합 니 다.이 방법 은 우리 가 CountDownTimer 클래스 를 만 들 때 재 작성 한 적 이 있 습 니 다.그 안에 우리 가 카운트다운 으로 보 여 준 구체 적 인 논 리 를 쓸 수 있다.이로써 전체 절차 가 끝났다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기