我想从计时器更新UI。这根本不是问题,但是当涉及到Gallery / ListViews时,它变得困难。我有一个自定义BaseAdapter的图库。我需要一个计数器用于每个(图库)项目(每个项目根据项目数据计算不同)。该计数器应该在主线程之外运行。另外,当只有一个项目可见时,我不想为库的10个项目运行10个线程。定义处理程序并在适配器中启动线程(计数)getView() - 项目/视图可见时的方法不是问题。我可以想到类似下面的代码:
public class MyAdapter extends BaseAdapter {
static class ViewHolder {
//...
public Handler myHandler;
}
public View getView(int position, View convertView, ViewGroup parent) {
//...
// getView() gets called indefinite so first remove callback because it may be added already
holder.myHandler.removeCallbacks(myRunnable);
holder.myHandler.postDelayed(myRunnable, 0);
//...
}
static class ViewHolder {
//...
public Handler myHandler;
}
public View getView(int position, View convertView, ViewGroup parent) {
//...
// getView() gets called indefinite so first remove callback because it may be added already
holder.myHandler.removeCallbacks(myRunnable);
holder.myHandler.postDelayed(myRunnable, 0);
//...
}
问题是删除不再可见的视图的回调,因为在getView()中我注意到视图变得可见但我不知道如何获取视图(从而获得持有者及其处理程序)删除回调后变得不可见。
是否有(另一种)方法可以解决这个问题?
答案 0 :(得分:2)
找到一个干净的解决方案(如果有人需要这样的东西)。我需要更新TextView以设置新的计数器值(每秒)。
在BaseAdapters getView中,我将TextViews添加到WeakHashMap。 TextView是地图的关键。如果不再引用密钥,则将删除键/值映射。所以我不会导致内存泄漏。 GarbageCollector完成了这项工作。
线程计算“计数器对象”并使用相应的值刷新TextViews(GarbageCollector一直运行,所以在我的情况下,地图主要包含3个项目,因为图库只显示一个项目。由于GarbageCollection,地图得到通过列表/图库快速滚动时,特别是“未使用的”TextViews立即清除
BaseAdapter的getView():
private WeakHashMap<TextView, Integer> counterMap = new WeakHashMap<TextView,Integer>();
private Handler counterHandler = new Handler();
public View getView(...) {
//...
counterMap.put(holder.tvCounter, position);
//...
}
柜台:
// Thread decrementing the time of the counter objects and updating the UI
private final Runnable counterTimeTask = new Runnable() {
public void run() {
//...
// decrement the remaining time of all objects
for (CounterData data : counterDataList)
data.decrementTimeLeftInSeconds();
// iterate through the map and update the containing TextViews
for (Map.Entry<TextView, Integer> entry : counterMap.entrySet()) {
TextView tvCounter = entry.getKey();
Integer position = entry.getValue();
CounterData data = counterDataList.get(position);
long timeLeftInSeconds = data.getTimeLeftInSeconds();
tvCounter.setText(" " + timeLeftInSeconds);
}
if (yourCondition)
counterHandler.postDelayed(this, 1000);
}
};
启动/停止计数器:
public void startCounter() { counterHandler.post(counterTimeTask); }
public void stopCounter() { counterHandler.removeCallbacks(counterTimeTask); }