倒计时计时器,在实际时间前 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 秒计数的主要内容,如果未能解决你的问题,请参考以下文章