倒计时计时器,在实际时间前 2 秒计数

Posted

技术标签:

【中文标题】倒计时计时器,在实际时间前 2 秒计数【英文标题】:Countdown Timer sometime, counts 2 seconds before the actual time 【发布时间】:2016-11-28 18:29:32 【问题描述】:

我试图在列表视图实现中创建一个倒数计时器。每个列表项都有一个可以启动或停止的单独倒数计时器。但是我注意到,如果我在列表中添加第一个计时器并设置它的时间。当我启动计时器时,它比实际时间少两秒。例如,如果我添加了 12 秒的倒计时。然后它会从 10 开始计数。但是当倒计时开始时,我添加了另一个新计时器并设置了它的时间,它从给定的确切时间开始。仅当列表中没有其他计数器或所有计数器都已停止且未倒计时时,新计数器才会在错误的时间启动。同样,只有在其他计时器倒计时时,它才会开始正确的时间。如果有人可以帮助我找出问题所在,我将不胜感激。这几天我一直在看代码。

这是我的适配器类

public class CustomAdapterCounter extends ArrayAdapter<CounterData> 

private final LayoutInflater mInflater;
Context context;
Uri sound = Uri.parse("android.resource://com.tattooalarmclock.free/" + R.raw.counter);
String counterString = "";
private List<ViewHolder> lstHolders;
private List<CounterData> list = new ArrayList<CounterData>();
private Handler mHandler = new Handler();
private Runnable updateRemainingTimeRunnable = new Runnable() 
    @Override
    public void run() 
        synchronized (lstHolders) 
            long currentTime = System.currentTimeMillis();
            for (ViewHolder holder : lstHolders) 
              //  if(!holder.counterData.isStopped)
                    holder.updateTimeRemaining(System.currentTimeMillis());
            
        
    
;

public CustomAdapterCounter(Context context, List<CounterData> l) 
    super(context, 0, l);
    this.context = context;
    lstHolders = new ArrayList<>();
    list = l;
    mInflater = LayoutInflater.from(context);

    for(int i=0; i<list.size(); i++) 
        CounterData[] array = list.toArray(new CounterData[list.size()]);
        if(!array[i].isStopped)
            startUpdateTimer();
    


public double getScreenSize() 
    DisplayMetrics dm = new DisplayMetrics();
    WindowManager windowManager = (WindowManager) context
            .getSystemService(Context.WINDOW_SERVICE);
    windowManager.getDefaultDisplay().getMetrics(dm);
    int width = dm.widthPixels;
    int height = dm.heightPixels;
    int dens = dm.densityDpi;
    double wi = (double) width / (double) dens;
    double hi = (double) height / (double) dens;
    double x = Math.pow(wi, 2);
    double y = Math.pow(hi, 2);
    double screenInches = Math.sqrt(x + y);

    return screenInches;



private void startUpdateTimer() 
    Timer tmr = new Timer();
    tmr.schedule(new TimerTask() 
        @Override
        public void run() 
            mHandler.post(updateRemainingTimeRunnable);
        
    , 1000, 1000);


public static <T> List<T> stringToArray(String s, Class<T[]> clazz) 
    T[] arr = new Gson().fromJson(s, clazz);
    return Arrays.asList(arr); //or return Arrays.asList(new Gson().fromJson(s, clazz)); for a one-liner



public boolean getListSharedPreferences() 

    SharedPreferences sharedPreferences = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE);

    if (sharedPreferences.getString("CL", null) != null) 
            counterString = sharedPreferences.getString("CL", null);
            Gson gson = new Gson();
            TypeToken<List<CounterData>> token = new TypeToken<List<CounterData>>() ;
            list = gson.fromJson(counterString, token.getType());
        return true;
    
    else
        return false;


public void saveListSharedPreferences(List counterList) 

    Gson gson = new Gson();
    counterString = gson.toJson(counterList);
    SharedPreferences sharedPreferences = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE);
    sharedPreferences.edit().putString("CL", counterString).commit();



@Override
public View getView(final int position, View convertView, ViewGroup parent) 
    ViewHolder holder = null;

    if (convertView == null) 
        holder = new ViewHolder();
        if(getScreenSize() <= 4 )
        convertView = mInflater.inflate(R.layout.list_view_counter_small, parent, false);
        else
        convertView = mInflater.inflate(R.layout.list_view_item_counter, parent, false);
        holder.counterTextView = (TextView) convertView.findViewById(R.id.counterTextView);
        holder.stopCounter = (Button) convertView.findViewById(R.id.counterStopInList);
        holder.startCounter = (Button) convertView.findViewById(R.id.counterStartInList);
        holder.deleteCounter = (Button) convertView.findViewById(R.id.deleteCounter);
        convertView.setTag(holder);
        synchronized (lstHolders) 
            lstHolders.add(holder);
        

     else 
        holder = (ViewHolder) convertView.getTag();
    
    holder.setData2(getItem(position));

    final ViewHolder finalHolder = holder;
    holder.stopCounter.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            long store = finalHolder.counterData.expirationTime - System.currentTimeMillis();
            finalHolder.counterData.isStopped = true;
            finalHolder.counterData.expirationTime = store;
            finalHolder.stopCounter.setEnabled(false);
            finalHolder.stopCounter.getBackground().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
            finalHolder.startCounter.setEnabled(true);
            finalHolder.startCounter.getBackground().setColorFilter(null);
            list.set(position, finalHolder.counterData);
            saveListSharedPreferences(list);

       /*     if(getListSharedPreferences()) 
                System.out.println("List before change in stop button " + list.toString());
                list = stringToArray(counterString, CounterData[].class);
                list.set(position, finalHolder.counterData);
                System.out.println("List before change in stop button " + list.toString());
                saveListSharedPreferences(list);
            
            else 
                System.out.println(list.toString());
                list.set(position, finalHolder.counterData);
                System.out.println(list.toString());
                saveListSharedPreferences(list);
            
        */
        
    );

    holder.startCounter.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            finalHolder.counterData.expirationTime = System.currentTimeMillis() + finalHolder.counterData.expirationTime;
            finalHolder.counterData.isStopped = false;
            //finalHolder.counterData.expirationTime = System.currentTimeMillis() + finalHolder.counterData.expirationTime;
            //finalHolder.setData(finalHolder.counterData);
            finalHolder.startCounter.setEnabled(true);
            finalHolder.startCounter.getBackground().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
            finalHolder.stopCounter.setEnabled(true);
            finalHolder.stopCounter.getBackground().setColorFilter(null);
            list.set(position, finalHolder.counterData);
            saveListSharedPreferences(list);
            startUpdateTimer();
       /*     if(getListSharedPreferences()) 
                list = stringToArray(counterString, CounterData[].class);
                System.out.println("List before change in start button " + list.toString());
                list.set(position, finalHolder.counterData);
                System.out.println("List after change in start button " + list.toString());
                saveListSharedPreferences(list);
            
            else 
                list.set(position, finalHolder.counterData);
                saveListSharedPreferences(list);
             */
        
    );

    final ViewHolder finalHolder1 = holder;
    holder.deleteCounter.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
 /*           if(finalHolder1.mediaPlayer.isPlaying()) 
                finalHolder.mediaPlayer.stop();
          //      finalHolder.counterData.isSoundPlayedBefore = true;
             */
            list.remove(position);
            notifyDataSetChanged();
            saveListSharedPreferences(list);
        
    );


    return convertView;



 class ViewHolder 
 public TextView counterTextView;
 //public List<Long> l;
 CounterData counterData;
 Button startCounter;
 Button stopCounter;
 Button deleteCounter;
 boolean stop = false;
 long timeDiff;
// Context context;
// MediaPlayer mediaPlayer;
// List<CounterData> counterDataList;

 public void setData(CounterData item) 
     counterData = item;
     updateTimeRemaining(System.currentTimeMillis());
 

 public void setData2(CounterData item) 
     counterData = item;
     updateTimeRemaining(System.currentTimeMillis());
 

 public void updateTimeRemaining(long currentTime) 

     if (!counterData.isStopped) 
         timeDiff = counterData.expirationTime - currentTime;
         //System.out.println("Time Diff Inside Method " + timeDiff);
         if (timeDiff > 0) 
             int seconds = (int) (timeDiff / 1000) % 60;
             int minutes = (int) ((timeDiff / (1000 * 60)) % 60);
             int hours = (int) TimeUnit.MILLISECONDS.toHours(timeDiff);
             counterTextView.setText(hours + "H " + minutes + "M " + seconds + "S");
             stopCounter.setEnabled(true);
             stopCounter.getBackground().setColorFilter(null);
             startCounter.setEnabled(false);
             startCounter.getBackground().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
          else 
             counterTextView.setText("Times Up");
             startCounter.setEnabled(false);
             startCounter.getBackground().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
             stopCounter.setEnabled(false);
             stopCounter.getBackground().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
         //    Vibrator v = (Vibrator) this.context.getSystemService(Context.VIBRATOR_SERVICE);
             // Vibrate for 500 milliseconds
         //    v.vibrate(5000);
     /*        if(!counterData.isSoundPlayedBefore) 
                 mediaPlayer.start();
                 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() 
                     @Override
                     public void onCompletion(MediaPlayer mp) 
                         mediaPlayer.stop();
                     
                 );
                 counterData.isSoundPlayedBefore = true;
                 if(findIndex(counterData) != -1) 
                     int index = findIndex(counterData);
                     counterDataList.set(index,counterData);
                     saveListSharedPreferences(counterDataList);
                 
              */
         
     
     else 
         long store = counterData.expirationTime + System.currentTimeMillis() - currentTime;
         int seconds = (int) (store / 1000) % 60;
         int minutes = (int) ((store / (1000 * 60)) % 60);
         int hours = (int) TimeUnit.MILLISECONDS.toHours(store);
         counterTextView.setText(hours + "H " + minutes + "M " + seconds + "S");
         startCounter.setEnabled(true);
         startCounter.getBackground().setColorFilter(null);
         stopCounter.setEnabled(false);
         stopCounter.getBackground().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
     
 
 

这是我的 CounterData 类

class CounterData 
long expirationTime;
boolean isStopped;
boolean isSoundPlayedBefore;
int id;

public CounterData(long expirationTime, int id) 
    this.expirationTime = expirationTime;
    isStopped = true;
    isSoundPlayedBefore = false;
    this.id = id;


public String toString() 

    return String.valueOf("Remaining Time: " + TimeUnit.MILLISECONDS.toMinutes(this.expirationTime) + ":" + TimeUnit.MILLISECONDS.toSeconds(this.expirationTime));


public void setCounterID(int id) 
    this.id = id;


public int getCounterID() 
    return this.id;


 

我从小时、分钟和秒的数字选择器中添加时间。

 case R.id.counterStartStopButton:
            long hour = TimeUnit.HOURS.toMillis(numberPickerHour.getValue());
            long minute = TimeUnit.MINUTES.toMillis(numberPickerMinute.getValue());
            long second = TimeUnit.SECONDS.toMillis(numberPickerSecond.getValue());
      //      if(getListSharedPreferences()) 
                if(getCounterIDSharedPreferences()) 
                    counterID = counterID + 1;
                    list.add(new CounterData(hour + minute + second, counterID));
                    saveCounterIDSharedPreferences(counterID);
                
                else 
                    counterID = 1;
                    list.add(new CounterData(hour + minute + second, counterID));
                    saveCounterIDSharedPreferences(counterID);
                

更新 这是共享偏好代码

public void saveCounterIDSharedPreferences(int id) 

    SharedPreferences sharedPreferences = this.getSharedPreferences("com.example.app", Context.MODE_PRIVATE);
    sharedPreferences.edit().putInt("Counter ID123", id).commit();



public boolean getCounterIDSharedPreferences() 

    SharedPreferences sharedPreferences = this.getSharedPreferences("com.example.app", Context.MODE_PRIVATE);

    if (sharedPreferences.getInt("Counter ID123", -1) != -1) 
        counterID = sharedPreferences.getInt("Counter ID123", -1);
        return true;
    
    else
        return false;

【问题讨论】:

所以你的第一个计时器从 10 开始(延迟 2 秒),但之后一切正常? 如果没有其他计时器或者列表中的所有其他计时器都已暂停,如果我添加一个新计时器,它将从(实际时间-2秒)开始计数。如果列表中的其他计数器正在倒计时并且没有停止,并且如果我在这种情况下添加一个新计数器,它就会开始正常。 你能发布 CounterIdSharedPref 代码吗? 请查看原帖中的更新。我已经把代码贴在那里了。 我认为问题出在:tmr.schedule(new TimerTask()..., 1000, 1000);您已经延迟了 1 秒。如果你设置12s,那么它从11s开始,但是在你显示定时器之前还有一些代码执行时间,所以它变成了10.XXXs。由于您只显示整数部分,因此它变为 10s。 【参考方案1】:

结果对我有用的是更改计时器任务如下:

 private void startUpdateTimer() 
    Timer tmr = new Timer();
    tmr.schedule(new TimerTask() 
        @Override
        public void run() 
            mHandler.post(updateRemainingTimeRunnable);
        
    , 500, 500);

【讨论】:

以上是关于倒计时计时器,在实际时间前 2 秒计数的主要内容,如果未能解决你的问题,请参考以下文章

定时器里如何再累加计时

在 Grub 2.02 源代码中查找倒数计时器

在java中创建一个计数计时器(仅限秒和毫秒)

proteus-单片机-实现60秒倒计时器

倒计时时钟的 DispatcherTimer 问题

Multisim仿真10秒倒计时8路抢答器