我正在创建一个包含带有2列的ListVIEw的应用程序.在第一列上应显示倒计时,在第二列上显示一个附加文本,用于说明倒计时的内容.
下面你看到我的代码有效……或多或少.
我有一个包含多行的列表视图,计时器正在滴答作响.
一个问题是:
我的runnable中的set.Text()似乎覆盖了所有行.例如.第1行的runnable也设置为第2行和第3行,第2行的runnable也设置为1和3的文本,依此类推.这会导致第一列闪烁(具有正确的值和其他行的值).
如何为列表视图中的特定行设置文本?
下一个问题:
即使我从处理程序中删除回调,runnable也会继续运行.但是当活动处于后台或关闭时,不需要计时器滴答,我不想浪费系统资源.
我的活动:
public class TimerActivity extends ListActivity {MyTimerAdapter myTimerAdapter = null;ArrayList<Long> timerList = new ArrayList<Long>();ArrayList<String> textList = new ArrayList<String>();@OverrIDepublic voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.Listactivity); myTimerAdapter = new MyTimerAdapter(this, R.layout.row, R.ID.tv_timer, R.ID.tv_text); setlistadapter(myTimerAdapter);}@OverrIDeprotected voID onResume() { super.onResume(); refreshVIEw();}@OverrIDeprotected voID onPause() { myTimerAdapter.clear(); myTimerAdapter.notifyDataSetChanged(); super.onPause();}private voID refreshVIEw() { myTimerAdapter.clear(); timerList.clear(); textList.clear(); // some code to read database and fill // array timerList with a long value (used for displaying a countdown) // and textList with some additional text myTimerAdapter.add(timerList, textList); myTimerAdapter.notifyDataSetChanged();}}
我的适配器:
public class MyTimerAdapter extends ArrayAdapter<String> {private Activity mContext;private ArrayList<Long> mTimer;private ArrayList<String> mText;private int mVIEwID;private int mVIEwIDFIEldTimer;private int mVIEwIDFIEldText;private int ListSize;private ArrayList<Handler> handlerList = new ArrayList<Handler>();private ArrayList<TimerRunnable> runList = new ArrayList<TimerRunnable>();public MyTimerAdapter(Activity context, int textVIEwResID, int tv1, int tv2) { super(context, textVIEwResID); mContext = context; mVIEwID = textVIEwResID; mVIEwIDFIEldTimer = tv1; mVIEwIDFIEldText = tv2; ListSize = 0;}public voID add(ArrayList<Long> timer, ArrayList<String> text) { mTimer = timer; mText = text; ListSize = mText.size(); handlerList.clear(); runList.clear();}@OverrIDepublic voID clear() { super.clear(); int i; for (i=0; i<ListSize; i++) { handlerList.get(i).removeCallbacksAndMessages(runList.get(i)); runList.get(i).stopHandler(); }}@OverrIDepublic int getCount() { return ListSize;}@OverrIDepublic VIEw getVIEw(int position, VIEw convertVIEw, VIEwGroup parent) { VIEw v = convertVIEw; if (v == null) { LayoutInflater vi = mContext.getLayoutInflater(); v = vi.inflate(mVIEwID, null); } long timerline = mTimer.get(position); if (timerline != 0) { TextVIEw tvTimer = (TextVIEw) v.findVIEwByID(mVIEwIDFIEldTimer); if (tvTimer != null) { tvTimer.setTag(position); final Handler mTimerHandler = new Handler(); TimerRunnable timerTask = new TimerRunnable(tvTimer, tvTimer.getTag().toString(), timerline); mTimerHandler.post(timerTask); // save in array to stop later handlerList.add(mTimerHandler); runList.add(timerTask); } } String textline = mText.get(position); if (textline != null) { TextVIEw tvText = (TextVIEw) v.findVIEwByID(mVIEwIDFIEldText); if (tvText != null) { tvText.setText(textline); } } return v;}}
我的Runnable:
public class TimerRunnable implements Runnable {private TextVIEw tv;final Handler mTimerHandler = new Handler();String tag;long endtime;long sec;public TimerRunnable (TextVIEw tv, String tag, long endtime) { this.tv = tv; this.tag = tag; this.endtime = endtime;}public voID run() { if (tv.getTag().toString().equals(tag)) { Calendar cal = Calendar.getInstance(); sec = endtime - (cal.getTimeInMillis() / 1000); //endtime - aktuelle Zeit if (sec >= 0) { // some code formatting the time in seconds to something like hh:mm:ss (var String txt) tv.setText(txt); System.out.println(txt); // only for tests; so I Could see that runnable is still running mTimerHandler.postDelayed(this, 1000); } }}public voID stopHandler() { mTimerHandler.removeCallbacksAndMessages(null);}}
解决方法:
我会这样做:
>使用计时器
(http://developer.android.com/reference/java/util/Timer.html)和
让它每秒钟或其他任何时候定期运行.
>在ActivitIEs onCreate()中创建Timer对象,并在ActivitIEs onDestroy()中取消()更新计时器(或者更好地在onResume中启动它并在onPause()中取消它).这就是如何避免内存泄漏的最简单方法,即使活动已关闭,您的计时器也在运行.
>从正在运行的计时器更新ListVIEw.有两种选择:
>只需从计时器调用adapter.notifyDatasetChanged()即可.但这可能会导致“闪烁”的列表视图.但是,您可以尝试检查这是否可以在您的应用程序中工作,因为这是最简单的实现.
>直接更新ListVIEw中当前可见的TextVIEw
private voID updateTime(){int firstVisibleItemIndex = ListVIEw.getFirstVisibleposition();for (int i = 0; i < ListVIEw.getChildCount(); i++) { VIEw v = ListVIEw.getChildAt(i); YourItem item = (YourItem)adapter .getItem(firstVisibleItemIndex + i)); VIEwHolder vh = (VIEwHolder) v.getTag(); // Calculate the time somehow, i.e. call a methot on your data item vh.tvTimer.setText(item.getelapsedtime()); }}
}
所以我猜第二种选择是最好的.您可能想知道VIEwHolder是什么. VIEwHolder是一种提高ListVIEw性能的模式. http://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder
适配器的问题是,每次用户滚动时都会调用findVIEwByID(). findVIEwByID()是一种昂贵的方法调用,因为它必须遍历所有视图子节点以找到具有给定ID的节点.在您的简单适配器中,它可能不会产生太大影响(因为您只有一个子视图,TextVIEw).但VIEwHolder是您应该在Adapter实现中始终使用的东西
以上是内存溢出为你收集整理的Android:具有处理程序和runnable的ListView中的多个计时器. 2个问题全部内容,希望文章能够帮你解决Android:具有处理程序和runnable的ListView中的多个计时器. 2个问题所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)