Android的内部类的TextView引用时恢复活动 [英] Android Innerclass TextView reference when activity resumes

查看:155
本文介绍了Android的内部类的TextView引用时恢复活动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有延伸CountDownTimer一个内部类。基本上它的一个简单的倒数计时器,在活动更新一个TextView,当计时器结束播放声音。在code的内部类是:

I have a inner class that extends CountDownTimer. Basically its a simple countdown timer that updates a TextView in the activity and plays a sound when the timer is finished. The code for the inner class is:

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的的code是:

The code that creates and references the TextView is:

TextView timeLeft;

和在onCreate方法:

and in the onCreate method:

timeLeft=(TextView) findViewById(R.id.txtTimeLeft);

直到我旋转显示这工作得很好。此时计时器仍在运行,并在年底不播放声音,但它不更新的TextView。 TextView的是在类的顶部声明,并在活动的onCreate方法引用。如果我重新启动定时器,然后它的作品。我用Log.d检查是否onTick方法仍然得到调用,它是。我的猜测是,参考TextView的改变,但我无法弄清楚如何将其设置回计时器。我试着宣布在onTick方法一个TextView和更新认定它会再拿起TextView的当前实例的引用,但也没有工作。唯一的其他东西要注意的是,当用户点击一个按钮创建SetTimer的对象。这code是:

This works fine until I rotate the display. At that point the timer is still running and does play the sound at the end but it doesn't update the TextView. The TextView is declared at the top of the class and referenced in the onCreate method of the activity. If I restart the timer then it works. I used Log.d to check if the onTick method was still getting called and it was. My guess is that the reference to the TextView has changed but I can't figure out how to set it back to the timer. I tried declaring a TextView in the onTick method and updating that figuring it would then pick up a reference to the current instance of the TextView but that also didn't work. The only other thing to note is that the SetTimer object is created when the user clicks on a button. That code is:

timer=new SetTimer(interval, 100);

timer.start();

如何有SetTimer的不断更新TextView的屏幕旋转后?有什么想法

Any thoughts on how to have the SetTimer keep updating the TextView after the screen is rotated?

推荐答案

更新我完全重写了答案,因为我没有在第一眼您code看到一个可怕的事情。

Update I completely rewrote the answer as I did not notice a terrible thing in your code at first glance.

您可能泄漏资源和你的应用程序不会崩溃的事实 - 可能只是一个时间问题。首先,你内心的的SetTimer 类隐拥有一个参考的活动(我猜,你这宣告类的活动,不是吗?)。这prevents您的活动被垃圾收集,我想,这就是为什么你设置的值到的TextView 那就是输出时不会得到一个异常视线。

You are possibly leaking resources and the fact your app does not crash - could be just a matter of time. First of all, your inner SetTimer class implicitly holds a reference to Activity (I guess, you declared this class in Activity, did not you?). That prevents your Activity from being garbage collected, and I guess, that's why you do not get an Exception when setting a value to a TextView that is "out-of-sight".

所以,您应该声明你的类的私有静态类 静态类(内部类),或公共类(在它自己的文件)。这样一来,你就不会抱到你的活动的隐式引用并不会造成当它被摧毁了内存泄漏。

So you should either declare your class as private static class, static class (inner classes), or public class (in it's own file). That way, you will not hold an implicit reference to your Activity and will not cause a memory leak when it gets destroyed.

但现在你将无法访问的的TextView 直接,因为它是您的活动的成员类。让我们来解决这样的说法:

But now you won't be able to access a textview directly, as it is a member of your Activity class. Let's solve it that way:


  1. 里面声明SetTimer的接口:

  1. Declare an interface inside SetTimer:

interface OnTickUpdateListener{
    public void onTickUpdate(String text);
}


  • 宣布该接口的实例在你的SetTimer和修改构造函数:

  • Declare an instance of such interface in your SetTimer and modify constructor:

    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;
        }
    ...
    }
    


  • 让我们引发听众时,计时器滴答:

  • Let's trigger the listener when the timer ticks:

    @Override
    public void onTick(long millisec){
        if(listener != null){
            String t;
            t = String.valueOf(millisec);//or whatever
            listener.onTickUpdate(t);
        }
    }
    


  • 现在,让你的活动实现你的界面:

  • Now, make your Activity implement your interface:

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


  • 现在的困难的部分。我们需要在活动被破坏保存SetTimer的实例。这将是一个不错的技巧,把SetTimer的一个片段保留看不见里面的用户,将工作很像一个不朽的集装箱:)

    Now to the harder part. We need to save a SetTimer instance when Activity is destroyed. That would be a nice trick to put a SetTimer inside a retained Fragment invisible to user, that would work much like an "immortal container" :)


    1. 创建一个片段类:

    1. Create a Fragment class:

    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 MyActivity的方法:

  • And last, add your MyFragment in onCreate method of MyActivity:

    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();
    
            }
        }
    


  • 这样,我们才能恢复活动后休闲现有的片段,并MyFragment注册新MyActivity作为一名听众,将接收打勾更新。

    That way, we restore the existing fragment upon Activity recreation, and MyFragment registers new MyActivity as a listener, which will receive tick updates.

    PS:我从头开始写这并没有测试它,因此,如果您遇到任何错误 - 请张贴他们,所以我们可以工作了。

    PS: I wrote this from scratch and did not test it, so if you encounter any error - please post them so we could work the out.

    这篇关于Android的内部类的TextView引用时恢复活动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆