簡體   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