我在我的android應用程序中有一個ListView,它應該包含秒錶計時器以及每一行中的開始和暫停按鈕。問題是,當我在一行中啓動計時器,並且如果我在ListView中啓動另一行屬於另一行,則第二個也從第一個位於的同一時間開始。所以基本上他們不是獨立的。我如何修改我的代碼,以便每行都有一個獨立的計時器,並且只有當它按下(開始或停止)按鈕時纔會生效。ListView中的多個秒錶定時器
這裏是我的自定義adapater類
public class CustomAdapterStopWatch extends BaseAdapter {
private final LayoutInflater layoutInflater;
Context context;
public static List<String> timerList;
private long startTime = 0L;
private Handler customHandler;
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
public CustomAdapterStopWatch(Context context, List<String> timerList) {
this.context = context;
this.timerList = timerList;
layoutInflater = LayoutInflater.from(context);
customHandler = new Handler();
}
@Override
public int getCount() {
return timerList.size();
}
@Override
public Object getItem(int position) {
return timerList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.stop_watch_list_view, null);
holder = new CustomAdapterStopWatch.ViewHolder();
holder.timerTextView = (TextView) convertView.findViewById(R.id.timerInListView);
holder.startTimer = (Button) convertView.findViewById(R.id.startTimerInListView);
holder.pauseTimer = (Button) convertView.findViewById(R.id.stopTimerInListView);
holder.timerTextView.setTag(position);
holder.startTimer.setTag(position);
holder.pauseTimer.setTag(position);
convertView.setTag(holder);
// Alarm alarm = (Alarm) getItem(position);
} else {
holder = (CustomAdapterStopWatch.ViewHolder) convertView.getTag();
}
holder.timerTextView.setText(timerList.get(position));
holder.startTimer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startTime = SystemClock.uptimeMillis();
customHandler.postDelayed(new Runnable() {
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updatedTime/1000);
int mins = secs/60;
secs = secs % 60;
int milliseconds = (int) (updatedTime % 1000);
holder.timerTextView.setText("" + mins + ":"
+ String.format("%02d", secs) + ":"
+ String.format("%03d", milliseconds));
customHandler.postDelayed(this, 0);
}
}, 0);
}
});
holder.pauseTimer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
timeSwapBuff += timeInMilliseconds;
customHandler.removeCallbacks(new Runnable() {
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updatedTime/1000);
int mins = secs/60;
secs = secs % 60;
int milliseconds = (int) (updatedTime % 1000);
holder.timerTextView.setText("" + mins + ":"
+ String.format("%02d", secs) + ":"
+ String.format("%03d", milliseconds));
customHandler.postDelayed(this, 0);
}
});
}
});
return convertView;
}
,我使用的佈局文件是如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/timerInListView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="00:00:00"
android:textSize="25dp"
android:textColor="@color/colorGray"/>
<Button
android:id="@+id/stopTimerInListView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
android:text="Pause"
android:background="@color/colorGreen"/>
<Button
android:id="@+id/startTimerInListView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="22dp"
android:text="Start"
android:background="@color/colorGreen"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/stopTimerInListView"
android:layout_toStartOf="@+id/stopTimerInListView"
android:layout_marginEnd="22dp" />
</RelativeLayout>
中,我使用適配器的秒錶類是如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stop_watch);
listView = (ListView) findViewById(R.id.listViewInStopWatch);
timerList = new ArrayList<String>();
timerList.add("00:00:000");
timerList.add("00:00:000");
timerList.add("00:00:000");
timerList.add("00:00:000");
customAdapter = new CustomAdapterStopWatch(StopWatch.this, timerList);
listView.setAdapter(customAdapter);
}
UPDATE
我改變了代碼如下:
public class CustomAdapterStopWatch extends BaseAdapter {
private final LayoutInflater layoutInflater;
Context context;
public static List<TimerState> timerList;
private long startTime = 0L;
private Handler customHandler;
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
HashMap<ViewHolder,Integer> mHashHolder;
TimerState state;
public CustomAdapterStopWatch(Context context, final List<TimerState> timerList) {
this.context = context;
this.timerList = timerList;
layoutInflater = LayoutInflater.from(context);
customHandler = new Handler();
mHashHolder = new HashMap<ViewHolder,Integer>();
state = new TimerState();
// assuming you need to update the timer after every second.
customHandler.postDelayed(new Runnable() {
@Override
public void run() {
for (ViewHolder holder: mHashHolder.keySet()) {
state = timerList.get(mHashHolder.get(holder));
// update the state
}
}
}, 1000);
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.stop_watch_list_view, null);
holder = new CustomAdapterStopWatch.ViewHolder();
holder.timerTextView = (TextView) convertView.findViewById(R.id.timerInListView);
holder.startTimer = (Button) convertView.findViewById(R.id.startTimerInListView);
holder.pauseTimer = (Button) convertView.findViewById(R.id.stopTimerInListView);
holder.timerTextView.setTag(position);
holder.startTimer.setTag(position);
holder.pauseTimer.setTag(position);
convertView.setTag(holder);
mHashHolder.put(holder,position);
// Alarm alarm = (Alarm) getItem(position);
} else {
// holder is being used again, so need to update its new position
// following line should be synchronized if timer is updated
// in a separate thread
mHashHolder.put(holder, position);
holder = (CustomAdapterStopWatch.ViewHolder) convertView.getTag();
}
holder.timerTextView.setText(timerList.get(position).currentTime);
holder.startTimer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startTime = SystemClock.uptimeMillis();
if (state.isPaused) {
state.timeSinceStarted = String.valueOf(SystemClock.uptimeMillis());
state.isPaused = false;
} else {
// nothing
}
}
});
holder.pauseTimer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (state.isPaused) {
state.isPaused = true;
}
}
});
return convertView;
}
public void startTime(final TextView t) {
Runnable updateTimerThread = new Runnable() {
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updatedTime/1000);
int mins = secs/60;
secs = secs % 60;
int milliseconds = (int) (updatedTime % 1000);
t.setText("" + mins + ":"
+ String.format("%02d", secs) + ":"
+ String.format("%03d", milliseconds));
customHandler.postDelayed(this, 0);
}
};
}
但是經過我按下按鈕,沒有任何反應。我錯過了什麼嗎?
更新2
public CustomAdapterStopWatch(Context context, final List<TimerState> timerList) {
this.context = context;
this.timerList = timerList;
layoutInflater = LayoutInflater.from(context);
customHandler = new Handler();
mHashHolder = new HashMap<ViewHolder,Integer>();
state = new TimerState();
// assuming you need to update the timer after every second.
customHandler.postDelayed(new Runnable() {
@Override
public void run() {
for (ViewHolder holder: mHashHolder.keySet()) {
state = timerList.get(mHashHolder.get(holder));
long tmp;
if (!state.isPaused) {
tmp = SystemClock.uptimeMillis();
state.currentTime += tmp - state.timeSinceStarted;
state.timeSinceStarted = tmp;
}
updatedTime = state.currentTime;
int secs = (int) (updatedTime/1000);
int mins = secs/60;
secs = secs % 60;
int milliseconds = (int) (updatedTime % 1000);
// set the text of the view in holder
holder.timerTextView.setText("" + mins + ":"
+ String.format("%02d", secs) + ":"
+ String.format("%03d", milliseconds));
// update the state
}
}
}, 1000);
}
更新3
public class CustomAdapterStopWatch extends BaseAdapter {
private final LayoutInflater layoutInflater;
Context context;
public static List<TimerState> timerList;
private long startTime = 0L;
private Handler customHandler;
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
HashMap<ViewHolder,Integer> mHashHolder;
TimerState state;
public CustomAdapterStopWatch(final Context context, final List<TimerState> timerList) {
this.context = context;
this.timerList = timerList;
layoutInflater = LayoutInflater.from(context);
customHandler = new Handler();
mHashHolder = new HashMap<ViewHolder,Integer>();
state = new TimerState();
// assuming you need to update the timer after every second.
customHandler.postDelayed(new Runnable() {
@Override
public void run() {
for (ViewHolder holder: mHashHolder.keySet()) {
state = timerList.get(mHashHolder.get(holder));
long tmp = 0;
if (!state.isPaused) {
tmp = SystemClock.uptimeMillis();
state.currentTime += tmp - state.timeSinceStarted;
state.timeSinceStarted = tmp;
}
updatedTime = state.currentTime;
int secs = (int) (updatedTime/1000);
int mins = secs/60;
secs = secs % 60;
int milliseconds = (int) (updatedTime % 1000);
// set the text of the view in holder
holder.timerTextView.setText("" + mins + ":"
+ String.format("%02d", secs) + ":"
+ String.format("%03d", milliseconds));
// notifyDataSetChanged();
Toast.makeText(context,"I got here", Toast.LENGTH_SHORT).show();
// update the state
}
customHandler.postDelayed(this, 1000);
}
}, 1000);
}
@Override
public int getCount() {
return timerList.size();
}
@Override
public Object getItem(int position) {
return timerList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.stop_watch_list_view, null);
holder = new CustomAdapterStopWatch.ViewHolder();
holder.timerTextView = (TextView) convertView.findViewById(R.id.timerInListView);
holder.startTimer = (Button) convertView.findViewById(R.id.startTimerInListView);
holder.pauseTimer = (Button) convertView.findViewById(R.id.stopTimerInListView);
holder.timerTextView.setTag(position);
holder.startTimer.setTag(position);
holder.pauseTimer.setTag(position);
convertView.setTag(holder);
mHashHolder.put(holder,position);
// Alarm alarm = (Alarm) getItem(position);
} else {
// holder is being used again, so need to update its new position
// following line should be synchronized if timer is updated
// in a separate thread
mHashHolder.put(holder, position);
holder = (CustomAdapterStopWatch.ViewHolder) convertView.getTag();
}
holder.timerTextView.setText(String.valueOf(timerList.get(position)));
holder.startTimer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startTime = SystemClock.uptimeMillis();
if (state.isPaused) {
state.timeSinceStarted = SystemClock.uptimeMillis();
state.isPaused = false;
} else {
// nothing
}
}
});
holder.pauseTimer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!state.isPaused) {
state.isPaused = true;
}
}
});
return convertView;
}
public void startTime(final TextView t) {
Runnable updateTimerThread = new Runnable() {
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updatedTime/1000);
int mins = secs/60;
secs = secs % 60;
int milliseconds = (int) (updatedTime % 1000);
t.setText("" + mins + ":"
+ String.format("%02d", secs) + ":"
+ String.format("%03d", milliseconds));
customHandler.postDelayed(this, 0);
}
};
}
private class ViewHolder {
TextView timerTextView;
Button startTimer;
Button pauseTimer;
}
}
感謝您的回答。但我仍然沒有得到如何在兩個按鈕和處理程序函數的偵聽器中使用timerstate數組。 –
邏輯將類似於你編碼的內容,但對於每個單獨的計時器。它將進入OnScroll方法。 –
這實際上很整潔。我非常喜歡這個解決方案。這比使用與處理程序結合的線程更好。如果我想一想,應該節省資源。 @Dev先生,所以你必須做的是將你的邏輯從'holder.startTimer.setOnClickListener'放入'OnScrol'l方法中。改變它有點使它適用於新的邏輯,它應該工作 – Nico