为什么我的Java对象在方向更改后引用旧活动?

时间:2014-06-23 16:19:18

标签: android android-activity android-orientation android-context android-side-navigation

背景

我有一个使用DrawerLayout的FragmentActivity。我创建了一个名为NavDrawerManager的类来抽象出用于处理抽屉布局的代码。要构造此对象,我需要传入并保留对Activity的引用。我使用此活动引用来调用findViewById(),并且在创建列表适配器等时也使用活动作为上下文。我在活动中保留对NavDrawerManager对象的引用,以便我可以在抽屉布局上执行回调和操作

UPDATE:根据Xaver的建议,我切换到将FragmentActivity扩展为NavDrawerActivity。超类不处理我的活动中的NavDrawerManager对象,而是处理导航抽屉代码。查看更新的代码。

问题:

一切正常,直到我改变方向。更改方向后,我的NavDrawerActivity似乎仍然引用旧布局。我这样说是因为我在DrawerLayout中有一个进度条和几个按钮,我试图更新,但它们没有反映更新。

当我调用Activity.findViewById()获取进度条并使其可见时,它不会显示任何更改,也不会显示对按钮的任何更改。注意:Activity.findViewById()不返回null。但是,如果我在更改方向之前执行相同的操作,则进度条和按钮会显示相应的更改。

代码:

NavDrawerActivity:

public class NavDrawerActivity extends LowProfileFragmentActivity {
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;

    private ExpandableListView mDrawerList;
    private NavDrawerAdapter mListAdapter;

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        mDrawerToggle.onOptionsItemSelected(item);
        return super.onOptionsItemSelected(item);
    }

    //Called via subclass after setContentView    
    protected void setupNavDrawer() {
        initDrawerLayout();
        initDrawerList();
        setButton1();
        setButton2();
    }

    private void initDrawerLayout() {
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerToggle = getActionBarDrawerToggle();
        mDrawerLayout.setDrawerListener(mDrawerToggle);
    }

    private void initDrawerList() {
        mDrawerList = (ExpandableListView) mDrawerLayout
                .findViewById(android.R.id.list);

        mListAdapter = getNavDrawerAdapter();
    }

    private ActionBarDrawerToggle getActionBarDrawerToggle() {
        return new ActionBarDrawerToggle(this, mDrawerLayout,
                R.drawable.ic_navigation_drawer, 0, 0) {

            public void onDrawerClosed(View view) {

            }

            public void onDrawerOpened(View view) {

            }
        };
    }


    public void setDrawerLoading(boolean loading) {
        ProgressBar progressBar = (ProgressBar) mDrawerLayout
                .findViewById(R.id.progress_bar);
        Button button1 = (Button) this.findViewById(R.id.button1);
        Button button2 = (Button) this
                .findViewById(R.id.button2);

        /* None of the below changes appear after changing orientation */
        if (loading) {
            button1.setEnabled(false);
            button2.setEnabled(false);
            progressBar.setVisibility(View.VISIBLE);
        } else {
            progressBar.setVisibility(View.GONE);
            button1.setEnabled(true);
            button2.setEnabled(true);
        }
    }

    private void setButton1() {
        Button button1 = (Button) this.findViewById(R.id.button1);
        button1.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //do something
            }

        });
    }

    private void setButton2() {
        Button button2 = (Button) this
                .findViewById(R.id.button2);
        button2.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //do something
            }

        });
    }
}

为ExampleActivity:

public class ExampleActivity extends NavDrawerActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initUI();
    }

    private void initUI() {
        setContentView(R.layout.activity_sift);

        // Call the superclass method to set up the nav drawer
        setupNavDrawer();
    }
}

的AndroidManifest.xml:

<activity
    android:name="com.example.app.ExampleActivity"
    android:label="@string/app_name"
    android:launchMode="singleTop"
    android:theme="@style/AppTheme" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

1 个答案:

答案 0 :(得分:1)

如果您实施NavDrawerActivity而不是NavDrawerManager,会不会更容易?通常应该避免这样的事情。用户界面应仅由FragmentsActivities自行处理。

我理解你为什么要创建这样的NavDrawerManager,只是为了让整个事情可以重复使用,而且很多抽象都很棒,但是当它过度时它就会成为一个问题。根据OOP标准,不要过分关注完全抽象的所有内容。 Activity同时拥有NavigationDrawer并隐藏通知栏没有任何问题。如果你已经有一个Activity来实现这两个东西中的一个,你应该扩展它。你唯一的另一个选择是在第二个Activity中重新实现相同的行为,这几乎会破坏抽象的目的。


编辑:我已经重构并改进了你的代码,你真的不应该有这么多不同的方法,所有的设置都属于onCreate(),你为每个编写了额外的方法步骤只是介绍了其他错误的可能性。试试这个:

public abstract class NavDrawerActivity extends LowProfileFragmentActivity {

    private ActionBarDrawerToggle drawerToggle;
    private DrawerLayout drawerLayout;
    private ProgressBar progressBar;
    private Button button1;
    private Button button2;

    private ExpandableListView drawerList;
    private NavDrawerAdapter drawerListAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayout());

        this.drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        this.drawerToggle = new ActionBarDrawerToggle(this, this.drawerLayout, R.drawable.icon_drawer, R.string.drawer_open, R.string.drawer_close);
        this.drawerLayout.setDrawerListener(this.drawerToggle);

        this.drawerList = (ExpandableListView) this.drawerLayout.findViewById(android.R.id.list);
        this.progressBar = (ProgressBar) this.drawerLayout.findViewById(R.id.progress_bar);

        this.button1 = (Button) findViewById(R.id.button1);
        this.button1.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                //do something
            }
        });

        this.button2 = (Button) findViewById(R.id.button2);
        this.button2.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                //do something
            }
        });

        this.drawerListAdapter = new NavDrawerAdapter(...);
        this.drawerList.setAdapter(this.drawerListAdapter);
    }

    protected abstract int getLayout();

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        this.drawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        this.drawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        return this.drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
    }

    public void setDrawerLoading(boolean loading) {
        this.button1.setEnabled(!loading);
        this.button2.setEnabled(!loading);
        this.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE);
    }
}

如您所见,我使用名为getLayout()的抽象方法将正确的布局传递给setContentView()getLayout()必须由所有Activities实施NavDrawerActivityActivities扩展ExampleActivity,从而对已使用的布局进行子public class ExampleActivity extends NavDrawerActivity { @Override protected int getLayout() { return R.layout.activity_sift; } } 控制。

因此,{{1}}应如下所示:

{{1}}

我测试了一切,它对我有用。