从子活动返回后,活动实例字段为null

时间:2016-03-20 17:23:34

标签: java android android-lifecycle

我正在努力解决Android活动生命周期问题:当我从子活动返回活动时,所有实例变量都为null,即使它们应该在活动的onCreate()方法中初始化。如下所示,只要我继续活动,SignSearchActivity就可以正常工作。方向改变没有问题。只要我导航到子活动SignSearch_Video_Activity并再次向上导航,就会在SignSearchActivity.onStart()方法中抛出NullPointerException。正如您在日志输出中看到的那样,在onStart()方法之前实际调用了SignSearchActivity.onCreate()方法 。我在SignSearchActivity.onPostExecute()方法中遇到了一个非常类似的问题,但我找到了解决方法(参见下面的FIXME代码)。现在,我真的卡住了。

非常感谢任何帮助。

最佳

的Matthias

搜索字符串会触发正常的生命周期流(最后是实例hashCode)

03-20 17:34:25.187 5980-5980/de.foo.bar.baz D/SignBrowserUIFragment: onPause
03-20 17:34:25.201 5980-5980/de.foo.bar.baz D/SignSearchActivity: onCreate() 81236595
03-20 17:34:25.250 5980-5980/de.foo.bar.baz D/SignSearchActivity: setupRecyclerView() 81236595
03-20 17:34:25.251 5980-5980/de.foo.bar.baz D/SignSearchActivity: setupSupportActionBar() 81236595
03-20 17:34:25.252 5980-5980/de.foo.bar.baz D/SignSearchActivity: initSignSearchTaskFragment() 81236595
03-20 17:34:25.253 5980-5980/de.foo.bar.baz D/SignSearchActivity: onStart() 81236595
03-20 17:34:25.254 5980-5980/de.foo.bar.baz D/SignSearchActivity: onPreExecute 81236595
03-20 17:34:25.257 5980-6295/de.foo.bar.baz D/SignDAO: Opening database.
03-20 17:34:25.261 5980-6295/de.foo.bar.baz I/SQLiteAssetHelper: successfully opened database signs.db
03-20 17:34:25.262 5980-6295/de.foo.bar.baz D/SignDAO: Reading signs with name_locale_de like: ma
03-20 17:34:25.264 5980-6295/de.foo.bar.baz D/SignDAO: Closing database.
03-20 17:34:25.311 5980-5980/de.foo.bar.baz D/SignSearchActivity: onCreateOptionsMenu()81236595
03-20 17:34:25.326 5980-5980/de.foo.bar.baz D/SignSearchActivity: onPostExecute 81236595
03-20 17:34:25.382 5980-5980/de.foo.bar.baz D/MainActivity: onSaveInstance
03-20 17:34:25.390 5980-5980/de.foo.bar.baz D/SignBrowserUIFragment: onSaveInstance

方向更改将saveInstance并创建SignSearchActivity的新实例(最后请参阅hashCode)

03-20 17:36:21.849 5980-5980/de.foo.bar.baz D/SignSearchActivity: onPause()81236595
>> 03-20 17:36:21.849 5980-5980/de.foo.bar.baz D/SignSearchActivity: onSaveInstanceState() 81236595
03-20 17:36:21.862 5980-6039/de.foo.bar.baz E/Surface: getSlotFromBufferLocked: unknown buffer: 0xb87d8f40
>> 03-20 17:36:21.898 5980-5980/de.foo.bar.baz D/SignSearchActivity: onCreate() 169372560 
03-20 17:36:21.914 5980-5980/de.foo.bar.baz D/SignSearchActivity: setupRecyclerView() 169372560
03-20 17:36:21.914 5980-5980/de.foo.bar.baz D/SignSearchActivity: setupSupportActionBar() 169372560
03-20 17:36:21.933 5980-5980/de.foo.bar.baz D/SignSearchActivity: onStart() 169372560
03-20 17:36:21.933 5980-5980/de.foo.bar.baz D/SignSearchActivity: onPreExecute 169372560
03-20 17:36:21.939 5980-6296/de.foo.bar.baz D/SignDAO: Opening database.
03-20 17:36:21.945 5980-6296/de.foo.bar.baz I/SQLiteAssetHelper: successfully opened database signs.db
03-20 17:36:21.946 5980-6296/de.foo.bar.baz D/SignDAO: Reading signs with name_locale_de like: ma
03-20 17:36:21.947 5980-6296/de.foo.bar.baz D/SignDAO: Closing database.
03-20 17:36:21.973 5980-5980/de.foo.bar.baz D/SignSearchActivity: onCreateOptionsMenu()169372560
03-20 17:36:21.994 5980-5980/de.foo.bar.baz D/SignSearchActivity: onPostExecute 169372560

点击一个标志也会保存实例

03-20 17:56:54.415 5980-5980/de.foo.bar.baz D/SignSearchActivity: onTxtSignNameClicked() 169372560
03-20 17:56:54.456 5980-5980/de.foo.bar.baz D/SignSearchActivity: onPause()169372560
03-20 17:56:54.472 5980-5980/de.foo.bar.baz D/SignSearchVideoActivity: onCreate()24174267
03-20 17:56:54.509 5980-5980/de.foo.bar.baz D/SignVideoUIFragment: onCreateView
03-20 17:56:54.644 5980-5980/de.foo.bar.baz D/SignVideoUIFragment: onActivityCreated
03-20 17:56:55.129 5980-5980/de.foo.bar.baz D/MediaPlayer: getMetadata
>> 03-20 17:56:55.182 5980-5980/de.foo.bar.baz D/SignSearchActivity: onSaveInstanceState() 169372560
03-20 17:56:55.614 5980-6001/de.foo.bar.baz W/MediaPlayer: info/warning (3, 0)

单击homeAsUpIndicator将导致SignSearchActitivity中出现NullPointerException

03-20 18:02:40.552 1625-1625/de.foo.bar.baz D/SignSearchVideoActivity: onPause()24174267
03-20 18:02:40.635 1625-1625/de.foo.bar.baz D/SignSearchActivity: onCreate() 188070473
03-20 18:02:40.654 1625-1625/de.foo.bar.baz D/SignSearchActivity: onStart() 188070473
03-20 18:02:40.659 1625-1625/de.foo.bar.baz D/AndroidRuntime: Shutting down VM
03-20 18:02:40.672 1625-1625/de.foo.bar.baz E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                                 Process: de.foo.bar.baz, PID: 1625
                                                                                                 java.lang.RuntimeException: Unable to start activity ComponentInfo{de.foo.bar.baz/de.foo.bar.baz.sign_browser.search.SignSearchActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean de.foo.bar.baz.sign_browser.search.SignSearchTaskFragment.isRunning()' on a null object reference
                                                                                                     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2426)
                                                                                                     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490)
                                                                                                     at android.app.ActivityThread.-wrap11(ActivityThread.java)
                                                                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354)
                                                                                                     at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                                     at android.os.Looper.loop(Looper.java:148)
                                                                                                     at android.app.ActivityThread.main(ActivityThread.java:5443)
                                                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
                                                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
                                                                                                  Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean de.foo.bar.baz.sign_browser.search.SignSearchTaskFragment.isRunning()' on a null object reference
                                                                                                     at de.foo.bar.baz.sign_browser.search.SignSearchActivity.onStart(SignSearchActivity.java:91)
                                                                                                     at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1260)
                                                                                                     at android.app.Activity.performStart(Activity.java:6261)
                                                                                                     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2389)
                                                                                                     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490) 
                                                                                                     at android.app.ActivityThread.-wrap11(ActivityThread.java) 
                                                                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354) 
                                                                                                     at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                                     at android.os.Looper.loop(Looper.java:148) 
                                                                                                     at android.app.ActivityThread.main(ActivityThread.java:5443) 
                                                                                                     at java.lang.reflect.Method.invoke(Native Method) 
                                                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728) 
                                                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 

SignSearchActivity

package de.foo.bar.baz.sign_browser.search;

import android.app.FragmentTransaction;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

import de.foo.bar.baz.R;
import de.foo.bar.baz.database.Sign;
import de.foo.bar.baz.sign_browser.search.video.SignSearchVideoActivity;
import de.foo.bar.baz.sign_browser.video.SignVideoUIFragment;

public class SignSearchActivity extends AppCompatActivity implements SignSearchTaskFragment.TaskCallbacks {

    private static final java.lang.String KEY_QUERY = "sign_browser_search_query";
    private static final String TAG_TASK_FRAGMENT = "sign_browser_search_task_fragment";
    private static final String TAG = SignSearchActivity.class.getSimpleName();
    private SignSearchTaskFragment signSearchTaskFragment;
    private String query = StringUtils.EMPTY;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate() " + this.hashCode());
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search_activity);
        if (null != savedInstanceState) {
            this.query = savedInstanceState.getString(KEY_QUERY);
        } else {
            final Intent intent = getIntent();
            if (!(Intent.ACTION_SEARCH.equals(intent.getAction()))) {
                return;
            }
            this.query = intent.getStringExtra(SearchManager.QUERY);
        }
        setupRecyclerView();
        setupSupportActionBar();
        this.signSearchTaskFragment = (SignSearchTaskFragment) getFragmentManager().findFragmentByTag(TAG_TASK_FRAGMENT);
        if (null == this.signSearchTaskFragment) {
            initSignSearchTaskFragment();
        }
    }

    private void initSignSearchTaskFragment() {
        Log.d(TAG, "initSignSearchTaskFragment() " + this.hashCode());
        this.signSearchTaskFragment = new SignSearchTaskFragment();
        final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        fragmentTransaction.add(signSearchTaskFragment, TAG_TASK_FRAGMENT);
        fragmentTransaction.commit();
    }

    private void setupRecyclerView() {
        Log.d(TAG, "setupRecyclerView() " + this.hashCode());
        final RecyclerView recyclerView = (RecyclerView) this.findViewById(R.id.signSearchRecyclerView);
//        recyclerView.setHasFixedSize(true); // performance fix
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(new SignSearchAdapter(new ArrayList<Sign>(), this));
    }

    private void setupSupportActionBar() {
        Log.d(TAG, "setupSupportActionBar() " + this.hashCode());
        final ActionBar supportActionBar = getSupportActionBar();
        if (null == supportActionBar) {
            throw new IllegalStateException("SupportActionBar is null. Should have been set in " +
                    "onCreate().");
        }
        supportActionBar.setTitle(getResources().getString(R.string.search_results) + StringUtils.SPACE + this.query);
        supportActionBar.setDisplayHomeAsUpEnabled(true);
    }

    @Override
    public void onStart() {
        Log.d(TAG, "onStart() " + this.hashCode());
        super.onStart();
//        if (null != this.signSearchTaskFragment) {
            if (!this.signSearchTaskFragment.isRunning()) {
                this.signSearchTaskFragment.start(this, query);
            }
//        }
    }

    @Override
    protected void onPause() {
        Log.d(TAG, "onPause()" + this.hashCode());
        super.onPause();
        if (signSearchTaskFragment.isRunning()) {
            this.signSearchTaskFragment.cancel();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        Log.d(TAG, "onCreateOptionsMenu()" + this.hashCode());
        final MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.options_sign_browser_search, menu);
        final SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        final MenuItem searchItem = menu.findItem(R.id.action_search);
        final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        return true;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        Log.d(TAG, "onSaveInstanceState() " + this.hashCode());
        super.onSaveInstanceState(outState);
        outState.putString(KEY_QUERY, this.query);
    }

    public void onTxtSignNameClicked(Sign sign) {
        Log.d(TAG, "onTxtSignNameClicked() " + this.hashCode());
        final Intent intent = new Intent(this, SignSearchVideoActivity.class);
        final Bundle bundle = new Bundle();
        bundle.putParcelable(SignVideoUIFragment.SIGN_TO_SHOW, sign);
        intent.putExtra(SignSearchVideoActivity.EXTRA, bundle);
        startActivity(intent);

//        final Intent intent = new Intent(this, LevelOneActivity.class);
//        final Bundle bundle = new Bundle();
//        bundle.putString(LevelOneActivity.FRAGMENT_TO_SHOW, SignVideoUIFragment.class.getSimpleName());
//        bundle.putParcelable(SignVideoUIFragment.SIGN_TO_SHOW, sign);
//        intent.putExtra(LevelOneActivity.EXTRA, bundle);
//        startActivity(intent);
    }

    @Override
    public void onPreExecute() {
        Log.d(TAG, "onPreExecute " + this.hashCode());
        /*no-op*/
    }

    @Override
    public void onProgressUpdate(int percent) {
        Log.d(TAG, "onProgressUpdate " + this.hashCode());
        /*no-op*/
    }

    @Override
    public void onCancelled() {
        Log.d(TAG, "onCancelled " + this.hashCode());
        /*no-op*/
    }

    @Override
    public void onPostExecute(List<Sign> result) {
        Log.d(TAG, "onPostExecute " + this.hashCode());
        // FIXME: After savedInstance has been called, this.recyclerview is null here, despite being
        // FIXME: set in the onCreated() method. Therefore a findViewById is necessary.
        final RecyclerView mRecyclerView = (RecyclerView) this.findViewById(R.id.signSearchRecyclerView);
        if (null == mRecyclerView) {
            throw new IllegalStateException("mRecyclerView is null");
        }
        mRecyclerView.swapAdapter(new SignSearchAdapter(result, this), false);
    }
}

SignSearch_Video_Activity

package de.foo.bar.baz.sign_browser.search.video;

import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;

import org.apache.commons.lang3.StringUtils;

import de.foo.bar.baz.R;
import de.foo.bar.baz.sign_browser.video.SignVideoUIFragment;

public class SignSearchVideoActivity extends AppCompatActivity {

    public static final String TAG = SignSearchVideoActivity.class.getSimpleName();
    public static final String EXTRA = "extra";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate()" + this.hashCode());
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search_video_activity);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        if (null != getSupportActionBar()) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            getSupportActionBar().setTitle(StringUtils.EMPTY);
        }
        final Intent intent = getIntent();
        final Bundle bundle = intent.getBundleExtra(EXTRA);
        if (null == bundle) {
            throw new IllegalArgumentException("The bundle supplied to the activity is null");
        }
        final Parcelable sign = bundle.getParcelable(SignVideoUIFragment.SIGN_TO_SHOW);
        final SignVideoUIFragment signVideoUIFragment = new SignVideoUIFragment();
        final Bundle args = new Bundle();
        args.putParcelable(SignVideoUIFragment.SIGN_TO_SHOW, sign);
        signVideoUIFragment.setArguments(args);
        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.replace(R.id.searchVideoActivityContentFrame, signVideoUIFragment, "SIGN_VIDEO_TAG");
        transaction.addToBackStack(null);
        transaction.commit();
    }

    @Override
    protected void onPause() {
        Log.d(TAG, "onPause()" + this.hashCode());
        super.onPause();
        setResult(RESULT_OK);
    }
}

1 个答案:

答案 0 :(得分:0)

自己想出来:

问题在于,即使执行了SignSearchActivity的onCreate()方法,它的重要部分也没有。这是因为子活动没有使用正确的意图调用SignSearchActivity(支持SearchView)。

所以这段代码

 if (!(Intent.ACTION_SEARCH.equals(intent.getAction()))) {
                return;
            }

意味着SignSearch.onCreate()方法在不应该返回时返回。

现在,SignSearchActivity将查询作为额外的意图传递给SignSearchVideoActivity。当SignSearchVideoActivity导航回SignSearchActivity时,它会再次传回原始查询。

修改了SignSearchActivity.onCreate()方法。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate() " + this.hashCode());
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search_activity);
        if (null != savedInstanceState) {
            this.query = savedInstanceState.getString(QUERY);
        } else {
            final Intent intent = getIntent();
            this.query = intent.getStringExtra(SearchManager.QUERY);
            Validate.notNull(this.query, "The query supplied to this activity is null!");
        }
        setupRecyclerView();
        setupSupportActionBar();
        this.signSearchTaskFragment = (SignSearchTaskFragment) getFragmentManager().findFragmentByTag(TAG_TASK_FRAGMENT);
        if (null == this.signSearchTaskFragment) {
            initSignSearchTaskFragment();
        }
    }

新SignSearchVideoActivity.onOptionItemsSelected()方法。

@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Log.d(TAG, "onOptionsItemSelected() " + this.hashCode());
        switch (item.getItemId()) {
            case android.R.id.home:
                final Intent upIntent = NavUtils.getParentActivityIntent(this);
                upIntent.putExtra(SearchManager.QUERY, this.originalQuery);
                NavUtils.navigateUpTo(this, upIntent);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }