gpt4 book ai didi

android - ListView 中的多个秒表计时器

转载 作者:行者123 更新时间:2023-11-29 01:15:07 25 4
gpt4 key购买 nike

我的 Android 应用程序中有一个 ListView,它应该包含秒表计时器以及每一行中的开始和暂停按钮。问题是,当我在一行中启动计时器时,如果我在 ListView 中启动属于另一行的另一个计时器,则第二个计时器也会从第一个计时器所在的时间开始。所以基本上他们不是独立的。我如何修改我的代码,以便每一行都有一个独立的计时器,并且它的时间只有在按下它的(开始或停止)按钮时才会生效。

这是我的自定义适配器类

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);
}

更新

我修改了如下代码:

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;
}
}

最佳答案

实际上你做错了两件事。

  1. 您为每个计时器使用相同的变量 updateTime。相反,您应该为每个计时器维护一个状态。所以最好为此开设一个单独的类(class)。例如

    class TimerState {     boolean isPaused = true;     long currentTime = 0;     String timeSinceStarted;    // matters only when the timer is started  }

So pass the array list of above class to your adapter. So that timerList will be arrayList of TimerState.

  @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stop_watch);

listView = (ListView) findViewById(R.id.listViewInStopWatch);
timerList = new ArrayList<TimerState>();


timerList.add(new TimerState());
timerList.add(new TimerState());
timerList.add(new TimerState());
timerList.add(new TimerState());

customAdapter = new CustomAdapterStopWatch(StopWatch.this, timerList);
listView.setAdapter(customAdapter);

}
  1. 这个有点棘手。适配器所做的是重用 View ,并且您正在更新某些 View 项的计时器(使用 postDelayed),即使它对用户不可见。因此,您应该只更新用户可见的那些 View 的计时器。我正在创建一个 HashMap ,它将保留用户可见的所有 View 的持有者,并且我们将有一个可运行的对象,它将仅更新那些 View 。

你的适配器将是

    public class CustomAdapterStopWatch extends BaseAdapter {    private final LayoutInflater layoutInflater;    Context context;    public static List timerList;    private long startTime = 0L;    private Handler customHandler;    long timeInMilliseconds = 0L;    long timeSwapBuff = 0L;    long updatedTime = 0L;    // this will contain the holder of all visible views    HashMap mHashHolder;    public CustomAdapterStopWatch(Context context, List timerList) {        this.context = context;        this.timerList = timerList;        layoutInflater = LayoutInflater.from(context);        customHandler = new Handler();        // assuming you need to update the timer after every second.        customHandler.postDelayed(new Runnable() {                @Override                public void run() {                    TimerState state;                    for (ViewHolderItem 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.t.setText("" + mins + ":"                          + String.format("%02d", secs) + ":"                          + String.format("%03d", milliseconds));                    }                    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) {        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);            mHashHolder.put(position, holder);            // 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            holder = (CustomAdapterStopWatch.ViewHolder) convertView.getTag();            mHashHolder.put(holder, position)        }        holder.timerTextView.setText(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                }                // logic for showing the timer will be in onScroll method            }        });        holder.pauseTimer.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (!state.isPaused) {                    state.isPaused = True                }            }        });        return convertView;    }

关于android - ListView 中的多个秒表计时器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40283183/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com