我正在努力解决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);
}
}
答案 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);
}