Android RecyclerView 조합 카운트다운 목록 인 스 턴 스 코드 구현

머리말
최근 수요 에 쫓 겨 나 테스트 를 거 쳐 접속 한 뒤 리 뷰 를 하지 않 는 기능 도 있다.한가 해 지 든 지 오래된 코드 를 다시 최적화 시 키 든 지,옛 것 을 배우 고 새로운 것 을 알 든 지,그래도 약간의 수확 과 발전 이 있다.
수요 TODO
단체 구 매 라 는 판 촉 방식 은 이미 매우 보편적 이 며,특히 모두 가 잘 아 는'그리고 저녁'은 더욱 잘 논다.이제 우 리 는 단체 구 매 카운트다운 목록 을 실현 하고'나머지:09:12:24.8'이라는 스타일 로 이 단체 가 끝 나 는 시간의 카운트다운 을 보 여 줘 야 한다.
기술 초보 분석
우선,시간 변화 에 관 한 것 은 먼저 Timer Task+Timer 라 는 타이머 조합 을 생각 합 니 다.목록 은 RecyclerView 라 고 말 할 필요 가 없습니다.UI 업데이트 와 관련 되 어 있 기 때문에 handler 가 item 을 업데이트 해 야 합 니 다.
초보 적 으로 우 리 는 두 가지 방식 을 생각 할 것 이다.
  • 아 이 템 당 하나의 timer 를 사용 하여 아 이 템 업데이트
  • timer 를 사용 하여 데이터 원본 을 업데이트 하고 item
  • 을 업데이트 합 니 다.
    두 가지 방법 은 각각 장단 점 이 있 습 니 다.그 다음 에 우 리 는 demo 를 통 해 구체 적 으로 비교 합 니 다.
    그 다음으로 안 드 로 이 드 시스템 의 시간 이 변 경 될 수 있 기 때문에 백 엔 드 를 통 해 돌아 오 는 groupFinishTime 에서 현재 시스템 시간 System.currentTimeMillis 를 보 여 주 는 남 은 시간 으로 줄 일 수 없습니다.그래서 우 리 는 먼저 인 터 페 이 스 를 할 때 백 엔 드 친구 와 약속 을 하 는 것 을 기억 합 니 다.큰 놈 은 저 에 게 남 은 시간(단 위 는 초 입 니까?밀리초 입 니까?모두 가능 하지만 대부분 초 를 줍 니 다)
    또 무슨 구덩이 가 있 을 지 생각 지도 못 했다.
  • 백 엔 드 가 바로 돌아 왔어요.1 초 남 았 는데 어 떡 하지?방법 이 없습니다.이 논 리 는 백 엔 드 가 엄밀 하면 임계 시간 대 r(st)q,아니면 우리 가 데 이 터 를 받 았 을 때 필 터 를 잘 합 니 다.
  • 백 엔 드 에서 데 이 터 를 가 져 오 는 네트워크 소모 시간+보 여 주 는 데 걸 리 는 시간(즉,나의 timer 가 언제 부터 시간 을 재 고 시작 하 는 소모 까지 초기 화 하 는 지)
    사실 안 드 로 이 드 자체 에 자신의 카운트다운 클래스 가 있 습 니 다.Countdown Timer,내부 실현 도 Handler 를 통 해 이 루어 집 니 다.주석 을 더 하면 모두 157 줄 이 고 프로그램 내부 소모 시간
  • 을 계산 합 니 다.
  • 목록 은 드 롭 다운 리 셋,드 롭 다운 로드 를 지원 합 니까?새로 고침 후 데이터 가 레이아웃 을 어 지 럽 힐 수 있 는 지 여 부 는 우리 가 고려 해 야 합 니 다.
  • RecyclerView 의 캐 시 메커니즘 이 화면 에 없 거나 화면 에 다시 돌아 오 는 데이터 에 미 치 는 영향
  • 타 이 머 를 사용 할 때 메모리 비용 과 메모리 누 출 을 고려 해 야 한다
  • 종합 적 으로 우 리 는 우리 가 해 야 할 일 을 확정 했다.
  • 레이아웃:SwipeRefreshLayout+RecyclerView
  • 타이머:CountDownTimer/Timer Task
  • 인터페이스 매개 변수:group Left Second(필수),group FinishTime(가장 좋 은 것 도 있 습 니 다),left MemberCount(아직 x 명 부족),leader Avater(단장 프로필 사진)
  • ok,그럼 우리 저녁 페이지 에 맞 춰 서 만 들 자.
    Coding
    1.아 이 템 마다 CountDownTimer 하나씩
    키 코드(kotlin)
    
    class GroupListAdapter(private val mContext: Context) : RecyclerView.Adapter<GroupListAdapter.GroupViewHolder>() {
    
     private var rList: List<GroupOrderBean>? = null
     private val countDownMap: SparseArray<CountDownTimer>?
     private var mPostion: Int = 0
     private var timesList: MutableList<Long> = ArrayList()
    
     init {
      countDownMap = SparseArray()
     }
    
     fun setGroupList(list: List<GroupOrderBean>?) {
      this.rList = list
      if (rList?.size!! > 0) {
       timesList = ArrayList()
       for (item in rList!!) {
        timesList.add(
         item.leftSecond * 1000 + System.currentTimeMillis()
        )
       }
      }
     }
    
    	//      
     fun cancelTimers() {
      if (countDownMap == null) {
       return
      }
      for (i in 0 until countDownMap.size()) {
       val cdt = countDownMap.get(countDownMap.keyAt(i))
       cdt?.cancel()
      }
     }
    
     override fun onBindViewHolder(holder: GroupViewHolder, position: Int) {
      if (rList == null ||rList!!.isEmpty()) {
       return
      }
      var countDownTimer: CountDownTimer? = countDownMap?.get(holder.tvLeftSecond.hashCode())
      countDownTimer?.cancel()
    
      val groupBean = rList!![position]
      if (groupBean.leftMember <= 0) {
       holder.tvLeftMember?.visibility = View.GONE
      }
      holder.tvLeftMember.text = "  ${groupBean.leftMember} "
      holder.tvLeftSecond.text = formatTime(groupBean.leftSecond * 1000)
    
      val lefttime = timesList[position] - System.currentTimeMillis()
    
      if (groupBean.leftSecond > 0) {
       if (lefttime <= 0) {
        holder.tvLeftSecond?.text = "  00:00:00.0"
        //TODO         
       } else {
        countDownTimer = object : CountDownTimer(lefttime, 100L) {
         override fun onTick(millisUntilFinished: Long) {
          holder.tvLeftSecond.text = formatTime(millisUntilFinished)
         }
    
         override fun onFinish() {
          holder.tvLeftSecond.text = "  00:00:00.0"
          //TODO         
         }
        }.start()
        countDownMap?.put(holder.tvLeftSecond.hashCode(), countDownTimer)
       }
    
      }
    
     }
    모든 Countdown Timer 를 SpaseArray 에 저장 하여 통일 적 으로 관리 합 니 다.view hodler 가 재 활용 되 는 것 을 피하 기 위해 서 는 timer 를 새로 만 들 었 습 니 다.모든 timer 에 view holder 의 hashcode 에 따라 spaseArray 에 저장 하 는 것 은 예전 에 listview 를 사용 할 때 tag 를 사용 하여 view holder 를 가 져 온 느낌 입 니 다.
    또 하 나 는 카운트다운 이 0 일 때 인터페이스 새로 고침 목록 을 다시 요청 하고 recyclerView 를 업데이트 하 며 이전의 모든 timer 를 멈 추고 Activity 를 종료 할 때 도 메모리 누 출 을 방지 해 야 합 니 다.
    이런 방법 은 데이터 가 비교적 적 을 때 괜 찮 습 니 다.페이지 데이터 가 너무 많 으 면 new 많은 Timer 가 소모 되 고 너무 큽 니 다.
    그래서 이 방안 은 조정 해 야 돼 요.
    2.모든 아 이 템 공용 타이머
    사고방식:하나의 timer 를 통 해 모든 item 데 이 터 를 업데이트 하고 handlerMessage 에서 메 시 지 를 받 아들 이 며 notifyItemChanged 를 통 해 item 을 업데이트 합 니 다
    키 코드
    handler 코드
    여기 서 주의해 야 할 점 이 있 습 니 다.notifyitemChanged(position:Int,payLoad:Any)를 사용 해 야 합 니 다.notifyItemChanged(position:Int)를 직접 사용 하여 레이아웃 을 업데이트 하 는 것 이 아니 라 페이지 가 깜빡 이지 않도록 해 야 합 니 다.
    
     init {
      mTask = CountTask()
    
      mHandler = object : Handler(Looper.getMainLooper()) {
       override fun handleMessage(msg: Message?) {
        if (msg?.what == 1) {
         if (rList?.size!! > 0) {
          notifyItemChanged(msg.arg1,rList!![msg.arg1])
         }
        }
       }
    
      }
     }
    list 데이터 초기 화
    
     fun setGroupList(list: List<GroupOrderBean>?) {
        this.rList = list
        if (rList?.size!! > 0) {
          cancelTimers()
          timesList = ArrayList()
          for (item in rList!!) {
            timesList.add(
              item.leftSecond * 1000
            )
          }
          mTimer = Timer()
          mTask = CountTask()
          mTimer?.schedule(mTask, 0, 100)
        }
      }
    
      fun cancelTimers() {
        mHandler.removeMessages(1)
          mTimer?.cancel()
          mTimer?.purge()
          mTimer = null
      }
    인 터 페 이 스 는 초 로 되 돌아 가 고 우 리 는 100 밀리초 로 새로 고침 해 야 하기 때문에 timesList 를 다른 시간 으로 저장 해 야 합 니 다.
    TimerTask 코드
    
      inner class CountTask : TimerTask() {
        override fun run() {
          if (timesList.isEmpty()) {
            return
          }
    
          var leftTime:Long
          for (i in timesList.indices) {
            if (timesList[i] <= 0) {
              continue
            }
            leftTime = timesList[i] - 100L
            if (leftTime <= 0) {
              timesList[i] = 0
              continue
            }
            timesList[i] = leftTime
    
            val message = Message.obtain()
            message.what = 1
            message.arg1 = i
            mHandler.sendMessage(message)
    
          }
        }
      }
    이전 스타일 그림:

    이 정도 면 충분 합 니까?
    no,no,no,카운트다운 종료 데이터 의 리 셋,드 롭 다운 리 셋,업 로드.이 페이지 는 좀 더 정교 해 야 한다.우리 의 목 표 는 별 바다 다.
    총결산
    이상 은 이 글 의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가 치 를 가지 기 를 바 랍 니 다.여러분 의 저희 에 대한 지지 에 감 사 드 립 니 다.

    좋은 웹페이지 즐겨찾기