[英]Activity instance fields null after returning from child activity
我正在為一個Android活動生命周期問題而苦苦掙扎:當我從其子活動返回活動時,即使所有實例變量都應該在該活動的onCreate()方法中進行了初始化,也均為空。 正如您在下面看到的,只要我繼續參加活動,SignSearchActivity都可以正常工作。 方向變化沒有問題。 一旦導航到子活動SignSearch_Video_Activity並再次導航回去,就會在SignSearchActivity.onStart()方法中引發NullPointerException。 你可以從日志輸出看到SignSearchActivity.onCreate() 方法的調用onStart()方法之前實際調用。 我在SignSearchActivity.onPostExecute()方法中遇到了一個非常相似的問題,但是我能夠找到一種解決方法(請參見下面的FIXME代碼)。 現在,我真的很困。
任何幫助,非常感謝。
最好
馬蒂亞斯
搜索字符串會觸發正常的生命周期流程(末尾為實例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
方向更改將保存實例並創建一個新的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);
}
}
我自己想通了:
問題在於,即使執行了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);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.