繁体   English   中英

活动恢复时的Android Innerclass TextView参考

[英]Android Innerclass TextView reference when activity resumes

我有一个扩展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保持更新T​​extView的任何想法?

更新我完全重写了答案,因为乍一看我没有发现代码中有什么可怕的事情。

您可能正在泄漏资源,而您的应用程序不会崩溃-这可能只是时间问题。 首先,您的内部SetTimer类隐式持有对Activity的引用(我想您是在Activity中声明了这个类,对吗?)。 这样可以防止对您的Activity进行垃圾回收,而且我想这就是为什么在为“视力不佳 ”的TextView设置值时没有得到Exception的原因。

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

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

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

     interface OnTickUpdateListener{ public void onTickUpdate(String text); } 
  2. 在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; } ... } 
  3. 让我们在计时器计时时触发监听器:

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

     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重新创建时恢复现有的片段,并且MyFragment将新的MyActivity注册为侦听器,该侦听器将接收刻度更新。

PS:我是从头开始编写的,并未对其进行测试,因此,如果您遇到任何错误-请张贴它们,以便我们解决。

随着您对textview的引用的更改,我想您已经添加了

android:configChanges="keyboardHidden|orientation|screenSize"

在您的AndroidManifest中,这样活动就不会在旋转时重新启动。

这是我的MainActivity代码,适合您

public class MainActivity extends Activity {

TextView timeLeft;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    timeLeft = (TextView)findViewById(R.id.textview);
    SetTimer st=new SetTimer(10000, 1000);
    st.start();
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);

    return true;
}


@Override
public void onConfigurationChanged(Configuration newConfig) {
    // TODO Auto-generated method stub
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.activity_main);
    timeLeft = (TextView)findViewById(R.id.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);
        }

}

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM