gpt4 book ai didi

Activity 恢复时的 Android 内部类 TextView 引用

转载 作者:塔克拉玛干 更新时间:2023-11-02 22:37:23 28 4
gpt4 key购买 nike

我有一个扩展 CountDownTimer 的内部类。基本上它是一个简单的倒数计时器,它更新 Activity 中的 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 在类的顶部声明,并在 Activity 的 onCreate 方法中引用。如果我重新启动计时器,它就会工作。我使用 Log.d 来检查 onTick 方法是否仍在被调用,它确实被调用了。我的猜测是对 TextView 的引用已更改,但我不知道如何将其设置回计时器。我尝试在 onTick 方法中声明一个 TextView 并更新它,然后计算它会获取对 TextView 的当前实例的引用,但这也没有用。唯一需要注意的是,当用户单击按钮时,将创建 SetTimer 对象。该代码是:

timer=new SetTimer(interval, 100);

timer.start();

关于如何让 SetTimer 在屏幕旋转后继续更新 TextView 有什么想法吗?

最佳答案

更新 我完全重写了答案,因为乍一看我没有注意到您的代码中有什么可怕的地方。

您可能正在泄漏资源,而您的应用不会崩溃这一事实 - 可能只是时间问题。首先,您的内部 SetTimer 类隐含地持有对 Activity 的引用(我猜,您在 Activity 中声明了这个类,不是吗?)。这可以防止您的 Activity 被垃圾收集,我想,这就是为什么在将值设置为“看不见”的 TextView 时您不会收到异常的原因".

因此您应该将您的类声明为私有(private)静态类静态类(内部类)或公共(public)类(在它自己的文件)。这样,您就不会持有对 Activity 的隐式引用,也不会在它被销毁时导致内存泄漏。

但现在您将无法直接访问 textview,因为它是您的 Activity 类的成员。让我们这样解决:

  1. 在 SetTimer 中声明一个接口(interface):

    interface OnTickUpdateListener{
    public void onTickUpdate(String text);
    }
  2. 在您的 SetTimer 中声明此类接口(interface)的实例并修改构造函数:

    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;
    }
    ...
    }
  3. 让我们在计时器计时时触发监听器:

    @Override
    public void onTick(long millisec){
    if(listener != null){
    String t;
    t = String.valueOf(millisec);//or whatever
    listener.onTickUpdate(t);
    }
    }
  4. 现在,让您的 Activity 实现您的界面:

    public class MyActivity extends Activity implements SetTimer.OnTickUpdateListener{
    @Override
    public void onTickUpdate(String text){
    textView.setText(text);
    }

现在是更难的部分。我们需要在 Activity 被销毁时保存一个 SetTimer 实例。将 SetTimer 放入用户不可见的保留 Fragment 中将是一个很好的技巧,它的工作方式很像“不朽容器”:)

  1. 创建 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
    }
    }
  2. 最后,在 MyActivity 的 onCreate 方法中添加您的 MyFragment:

    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 时恢复现有 fragment ,MyFragment 将新的 MyActivity 注册为监听器,它将接收滴答更新。

PS:我是从头开始写的,没有测试它,所以如果您遇到任何错误 - 请发布错误,以便我们解决问题。

关于 Activity 恢复时的 Android 内部类 TextView 引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22511248/

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