我有一个扩展 CountDownTimer 的内部类。基本上它是一个简单的倒计时器,用于更新活动中的 TextView 并在计时器完成时播放声音。内部类的代码是:
public class SetTimer extends CountDownTimer
{
public SetTimer(long millisInFuture, long countDownInterval)
{
super(millisInFuture, countDownInterval);
}
@Override
public void onFinish()
{
timeLeft.setText("0");
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r=RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
}
@Override
public void onTick(long millisUntilFinished)
{
String t;
t=String.format("%02d:%02d", TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished), TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished)
-TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)));
timeLeft.setText(t);
}
}
创建并引用 TextView 的代码是:
TextView timeLeft;
并在 onCreate 方法中:
timeLeft=(TextView) findViewById(R.id.txtTimeLeft);
在我旋转显示器之前,这一切正常。此时计时器仍在运行,并在最后播放声音,但它不会更新 TextView。 TextView 在类的顶部声明,并在活动的 onCreate 方法中引用。如果我重新启动计时器,它就会起作用。我使用 Log.d 检查 onTick 方法是否仍然被调用,确实如此。我的猜测是对 TextView 的引用已更改,但我不知道如何将其设置回计时器。我尝试在 onTick 方法中声明一个 TextView 并更新它,然后它会获取对 TextView 当前实例的引用,但这也不起作用。唯一需要注意的是,SetTimer 对象是在用户单击按钮时创建的。该代码是:
timer=new SetTimer(interval, 100);
timer.start();
关于如何让 SetTimer 在屏幕旋转后不断更新 TextView 有什么想法吗?
Update我完全重写了答案,因为我乍一看并没有注意到你的代码中有什么可怕的事情。
您可能会泄漏资源,而您的应用程序不会崩溃这一事实 - 可能只是时间问题。首先,你的内心SetTimer类隐式持有对Activity(我猜,你在 Activity 中声明了这个类,不是吗?)。这会阻止你Activity免于被垃圾收集,我猜,这就是为什么在将值设置为 a 时不会收到异常的原因TextView那是“看不见的”。
所以你应该将你的类声明为私有静态类, 静态类(内部类),或者公开课(在它自己的文件中)。这样,您将不会保留对 Activity 的隐式引用,并且在其被销毁时也不会导致内存泄漏。
但现在您将无法访问textview直接,因为它是您的成员Activity班级。我们这样解决吧:
-
在SetTimer内部声明一个接口:
interface OnTickUpdateListener{
public void onTickUpdate(String text);
}
-
在 SetTimer 中声明此类接口的实例并修改构造函数:
public class SetTimer extends ... {//this class IS IN IT's OWN FILE!!!!
private OnTickUpdateListener listener;
public void registerListener(OnTickUpdateListener listener){
this.listener = listener;
}
public void unregisterListener(){
this.listener = null;
}
...
}
-
让我们在计时器计时时触发监听器:
@Override
public void onTick(long millisec){
if(listener != null){
String t;
t = String.valueOf(millisec);//or whatever
listener.onTickUpdate(t);
}
}
-
现在,让您的 Activity 实现您的界面:
public class MyActivity extends Activity implements SetTimer.OnTickUpdateListener{
@Override
public void onTickUpdate(String text){
textView.setText(text);
}
现在到更困难的部分。当 Activity 被销毁时,我们需要保存一个 SetTimer 实例。将 SetTimer 放入对用户不可见的保留 Fragment 中将是一个很好的技巧,这将像“不朽容器”一样工作:)
-
创建一个Fragment类:
public class MyFragment extends Fragment{
public static final String TAG = MyFragment.class.getSimpleName();
private SetTimer timer;
private static final int interval = 10;
private MyActivity myActivity;
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
this.myActivity = (MyActivity) activity;
}
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setRetainInstanceState(true);
timer = new SetTimer(interval, 10);
timer.start();
}
@Override
public void onActivityCreated(Bundle state){
super.onActivityCreated(state);
timer.registerListener(myActivity);//activity should receive ticks
}
@Override
public void onDetach(){
super.onDetach();
timer.unregisterListener();//ensure we do not post a result to non-existing Activity
}
}
-
最后,将您的 MyFragment 添加到onCreate
我的活动方法:
public class MyActivity extends Activity implements SetTimer.OnTickUpdateListener{
private MyFragment fragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fm = getFragmentManager();
fragment = (MyFragment) fm.findFragmentByTag(MyFragment.TAG);
if(fragment == null){
fragment = new MyFragment();
fm.beginTransaction().add(R.id.container, fragment, MyFragment.TAG).commit();
}
}
这样,我们在 Activity 重新创建时恢复现有片段,并且 MyFragment 将新的 MyActivity 注册为侦听器,它将接收更新更新。
PS:这是我从头开始写的,没有测试它,所以如果您遇到任何错误 - 请发布它们,以便我们解决。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)