简体   繁体   中英

Strange behavior of initialization in Java

/**
 * Example Activity to demonstrate the lifecycle callback methods.
 */
public class ActivityA extends Activity {

    private String mActivityName;
    private TextView mStatusView;
    private TextView mStatusAllView;
    private StatusTracker mStatusTracker = StatusTracker.getInstance();
    private AlertDialog alertBox;
    private static int number = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);

        init();

        String output = getString(R.string.on_create) + number++;
        showAlertDialog(alertBox, output);
        mStatusTracker.setStatus(mActivityName, output);
        Utils.printStatus(mStatusView, mStatusAllView);
    }

    @Override
    protected void onStart() {
        super.onStart();
        mStatusTracker.setStatus(mActivityName, getString(R.string.on_start));
        Utils.printStatus(mStatusView, mStatusAllView);
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        mStatusTracker.setStatus(mActivityName, getString(R.string.on_restart));
        Utils.printStatus(mStatusView, mStatusAllView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mStatusTracker.setStatus(mActivityName, getString(R.string.on_resume));
        Utils.printStatus(mStatusView, mStatusAllView);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mStatusTracker.setStatus(mActivityName, getString(R.string.on_pause));
        Utils.printStatus(mStatusView, mStatusAllView);
    }

    @Override
    protected void onStop() {
        super.onStop();
        mStatusTracker.setStatus(mActivityName, getString(R.string.on_stop));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mStatusTracker.setStatus(mActivityName, getString(R.string.on_destroy));
        mStatusTracker.clear();
    }

    public void startDialog(View v) {
        Intent intent = new Intent(ActivityA.this, DialogActivity.class);
        startActivity(intent);
    }

    public void startActivityB(View v) {
        Intent intent = new Intent(ActivityA.this, ActivityB.class);
        startActivity(intent);
    }

    public void startActivityC(View v) {
        Intent intent = new Intent(ActivityA.this, ActivityC.class);
        startActivity(intent);
    }

    public void finishActivityA(View v) {
        ActivityA.this.finish();
    }

    private void showAlertDialog(AlertDialog ad, String msg) {
        ad.setTitle("Logging Msg");
        ad.setMessage(msg);
        ad.show();
    }

    private void init() {
        System.out.println("Value = before &&&&&&&&& " + alertBox);
        if (alertBox == null) { // Why always null?
            alertBox = new AlertDialog.Builder(this).create();
            mActivityName = getString(R.string.activity_a);
            mStatusView = (TextView) findViewById(R.id.status_view_a);
            mStatusAllView = (TextView) findViewById(R.id.status_view_all_a);
            Log.e("ActivityA", "Init done **************************************");
            Log.e("ActivityA", "Init done **************************************");
            System.out.println("Value = after &&&&&&&&&&& " + alertBox);
        }
    }
}

Only the very first time the init is called, I set alertBox and I thought the if block should not be executed any other time. But I am wrong, it runs every time init is being called. Why?

I came from Javascript, if I translate the above code into JS (similar), the if block is only evaluated once.

alertBox is a member variable of a the class, ie each instance of the class has its own copy. So if you have multiple instances of ActivityA each has its own alertBox all set to null initially.

If you want to share alertBox you need to declare it as static :

private static AlertDialog alertBox;

Although, this might result in (additional) problems in a multi-threaded application, so use with care!

You should check how your application follows the android activity lifecycle. The onCreate method gets called every time an Activity is created again (even if it existed before). Check if your onDestroy() method gets called. If the answer is yes, you now know how android handles its Activitys. See http://developer.android.com/training/basics/activity-lifecycle/starting.html for an in detail explanation.

However if the answer is no, there is something wrong on your activity handling. Maybe you recreate the same activity every time the user pushes a button etc. Maybe you finish() the activity somewhere. But this is just wild guessing.

alertBox is declared as an instance variable.

Maybe you should make alertBox a static variable if you only want to set it once for the class and not for every object instance.

Probably, the activity is destroyed and recreated, so the new object has alertBox as null.

You should not change it to an static variable, because alertBox holds a reference to the activity where it was created (I'm not sure if it would even work correctly in other instances of the activity), so if you saved it in a static variable, it would prevent the original activity from being collected by the GC (garbage collector).

Creating a new one in each instance of the activity is the right way to go (the way you are doing it now is fine).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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