开发者

A question on activity lifecycle and resource deletion/allocation

I've been puzzled very much by this lifecycle thing, so I did a little experiement. Long story short: The result shows that when a process is created after having been destroyed, UI objects allocated in the last session were all gone and need be re-created (which is expected). But other memory space allocated in the last session are still available for this session.

The surprise to me is: system's UI objects (like ListView) and memory space allocated by me are not destroyed at the same time. Why they don't die (or stay alive) at the same time???

See the experiement here:

public class PracticeActivity extends ListActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // If there is left-over value in G.count[99], then do not populate
        // the ListView. 
        if (G.count[99] == 0) {
            ListView lv = getListView();
            lv.setAdapter(new ArrayAdapter<String>(this, 
                android.R.layout.simple_list_item_1, m_Starbucks));
        }

        Log.d("TAG", MessageFormat.format("Created, count = {0,number}", G.count[99]));
        Log.d("TAG", MessageFormat.format("Starbucks = {0}", m_Starbucks[0]));
        G.count[99]++;                              // increment the count
        m_Starbucks[0] = "Coffee Frappuccino";      // and change the menu
    }

    @Override public void onRestart() { super.onRestart(); Log.d("TAG", "Restarted"); }
    @Override public void onStart() { super.onStart(); Log.d("TAG", "Started"); }
    @Override public void onResume() { super.onResume(); Log.d("TAG", "Resumed"); }
    @Override public void onPause() { super.onPause(); Log.d("TAG", "Paused"); }
    @Override public void onStop() { super.onStop(); Log.d("TAG", "开发者_StackOverflow社区Stopped"); }

    @Override public void onDestroy() { 
        super.onDestroy();
        if (isFinishing())
            Log.d("TAG", "Destroyed -- someone finished me");
        else
            Log.d("TAG", "Destroyed -- system needs resources");
    }

    private static final String[] m_Starbucks = {
        "Latte", "Cappuccino", "Caramel Macchiato", "Americano", "Mocha", 
        "White Mocha", "Mocha Valencia", "Cinnamon Spice Mocha", 
        "Toffee Nut Latte", "Espresso", "Espresso Macchiato", 
        "Espresso Con Panna"
    };
}

Here is the class G, defined in G.java file:

public class G {
    public static int[] count = new int[100];
}

Running this test produced the following results:

Created, count = 0
Starbucks = Latte
Started
Resumed
Paused
Stopped
Destroyed -- someone finished me
Created, count = 1
Starbucks = Coffee Frappuccino
Started
Resumed

In the first session, count[99]'s value was 0, so the program went to populate the ListView, so everything was fine.

In the 2nd session, count[99] still holds the value left over from the first session, so the program did not populate the ListView, in hope that the ListView would also be available too. But it's not, the result is a black screen. This means G.count[] was retained (and so is m_Starbucks[]) from last session, but the ListView didn't survive.

It's apparent that there's only one instance of PracticeActivity in the system, when this instance dies, both PracticeActivity and G classes should die too. But they didn't, they still retain values from the last session.

QUESTIONS:

  1. If count[] and m_Starbucks[] are still available, then this means PracticeActivity and G are both alive too. Then why the ListView is gone? Shouldn't all of them die or live at the same time?
  2. When I see some of my classes' members hold their old values from last session, can I trust that all of my classes' members are also valid??? I.e., does Android kill my resources in an all-or-none fashion? Or, it can delete some and leave some others? (This question shouldn't have existed in the first place, but seeing the result of the experiement, one starts to wonder.)

Can anybody shed some light on this? Much appreciated.


Static class members live as long as JVM (DVM) lives - which may be (and certainly is) longer than your activity lifecycle. Your activity could be destroyed, but static fields survive it.


If count[] and m_Starbucks[] are still available, then this means PracticeActivity and G are both alive too.

No. count and m_Starbucks are both declared static. Per Java documentation:

"Class Variables (Static Fields) A class variable is any field declared with the static modifier; this tells the compiler that there is exactly one copy of this variable in existence, regardless of how many times the class has been instantiated"

So say you do the following: (pretend this isn't an activity and you can conveniently just construct it)...

PracticeActivity example1 = new PracticeActivity();
PracticeActivity example2 = new PracticeActivity();

Then you do not have example1.m_Starbucks[0] and example2.m_Starbucks[0] as distinct variables. Instead, you just have PracticeActivity.m_Starbucks[0] and any specific instance of that class has the same variable. Therefore it is unaffected by (unrelated to!) the destruction of the actual instance of your Activity. And in fact, they exist, even if you have never constructed an instance of the class that contains them.

Also, if you change example1.m_Starbucks[0], you will find that example2.m_Starbucks[0] also has changed -- because, again, there's only one array.

The simple answer here is that you shouldn't be using static variables for this type of storage. It's safe to use static for constants and some other special cases, but never as member variables that you expect to hold attributes of a given instance of a class, that make that instance uniquely different from other classes.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜