我在Google Play上有一个应用程序,如果应用程序更新后再由用户重新打开,则应用程序会在后台崩溃。崩溃有时只会发生,这暗示某个地方会出现竞争。我很难调试这个并且自己只能重现这几次,尽管我有一些用户报告的堆栈跟踪。堆栈跟踪永远不会指向代码中的同一行,但堆栈跟踪始终通过Android中的performResumeActivity()
输入我的代码,因此在我的代码中输入onResume()
。请注意,这一点从未发生过,或者用户在任何其他上下文中报告的情况都比更新应用程序时要多(据我所知)。这并不意味着它只在更新应用程序时才会发生,但这是我看到崩溃发生的唯一方法。
(有时)重现的步骤:
adb install app-release-previous-version.apk
。performResumeActivity()
/ onResume()
崩溃。我将添加发生崩溃的Activity的代码。不会粘贴此崩溃的非重要代码,但请告诉我是否应添加更多代码。我在问题的最后粘贴了各种堆栈痕迹。
MyActivity(仅限重要部分)
public class MyActivity extends AppCompatActivity
{
private MyMainFragment myMainFragment = null;
private FilteredRecipes myFilteredRecipes = null;
private MyShoppingList myShoppingList = null;
private boolean mShouldReadAutomaticSave = false;
// <snip> other members
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mShouldReadAutomaticSave = savedInstanceState == null;
setContentView(R.layout.my_activity);
// Setup Toolbar / ActionBar.
Toolbar toolbar = (Toolbar) findViewById(R.id.my_main_toolbar);
setSupportActionBar(toolbar);
NavigationView navigationView = (NavigationView) findViewById(R.id.my_navigationview);
if (navigationView != null)
{
// <snip> Setup navigationView
}
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.my_drawer_layout);
if (drawerLayout != null)
{
// <snip> Setup DrawerLayout
}
if (myShoppingList == null) { myShoppingList = new MyShoppingList(this); }
if (myFilteredRecipes == null) { myFilteredRecipes = new MyFilteredRecipes(this); }
if (myMainFragment == null) { myMainFragment = new MyMainFragment(); }
if (savedInstanceState == null)
{
// Runs a thread to read recipes from an SQLite database. This is not the culprit.
filterAllRecipes(null);
}
else
{
restoreState(savedInstanceState); // See method below
}
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.fade_in, R.anim.none)
.replace(R.id.my_content_frame, myMainFragment, "main_fragment")
.commit();
}
@Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
if (myFilteredRecipes != null)
{
myFilteredRecipes.onSaveInstanceState(outState); // Restores from Bundle
}
if (myShoppingList != null)
{
myShoppingList.onSaveInstanceState(outState); // Restores from Bundle
}
if (myMainFragment != null)
{
getSupportFragmentManager().putFragment(outState, "myFragment", myMainFragment); // Restores from Bundle
}
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
}
private void restoreState(Bundle savedInstanceState)
{
myShoppingList.onRestoreInstanceState(savedInstanceState);
myFilteredRecipes.onRestoreInstanceState(savedInstanceState);
myMainFragment = (MyMainFragment)
getSupportFragmentManager().getFragment(savedInstanceState, "myFragment");
}
@Override
public void onResume()
{
super.onResume();
// These tests were added as an attempt to cure the crash.
// Probably fixed some of the crashes (stack traces below), but not the entire issue.
if (myShoppingList == null) { myShoppingList = new MyShoppingList(this); }
if (myFilteredRecipes == null) { myFilteredRecipes = new MyFilteredRecipes(this); }
if (myMainFragment == null)
{
myMainFragment = new MyMainFragment();
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.fade_in, R.anim.none)
.replace(R.id.my_content_frame, myMainFragment, "main_fragment")
.commit();
}
if (mShouldReadAutomaticSave) // Set in onCreate() when applicable
{
mShouldReadAutomaticSave = false;
final MyActivity mThis = this;
Thread loadAutomaticSaveThread = new Thread()
{
@Override
public void run()
{
// Load automatic save if any. Must be done last to avoid race condition in LoadShoppingListTaks.
JSONObject automaticSave = ShoppingListFileHandler.readAutomaticSavedShoppingList(mThis);
if (automaticSave != null)
{
// This task takes the JSON data from the file read above, reads data from an SQLite database and sets up the myShoppingList data.
// Calls back to MyActivity.onShoppingListLoaded() when done.
// NOTE: There has been a crash in here when myShoppingList was null. This was before the "== null" tests above was added.
new ShoppingListFileHandler.LoadShoppingListTask(mThis, myShoppingList, automaticSave, false).execute();
}
}
};
loadAutomaticSaveThread.setName("LoadAutomaticSaveThread");
loadAutomaticSaveThread.start();
}
}
// This is called from the LoadShoppingListTask when done.
@Override
public synchronized void onShoppingListLoaded()
{
if (myShoppingList != null)
{
// MyShoppingList.notifyDataSetChanged will call notifyDataSetChanged on a
// RecyclerView adapter in the main Fragment. There is a stack trace for this below.
myShoppingList.notifyDataSetChanged();
}
}
}
这就是发生崩溃的活动。以下是我得到的堆栈跟踪,其中一些是部分混淆的,因为我当时并不了解它的作用。
丢失片段的堆栈跟踪
注意:似乎我们得到的片段为null,即尝试重新启动Activity时可能为myMainFragment
为空。
java.lang.RuntimeException: Unable to resume activity {com.my.app/com.my.app.activities.MyActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f0f0089 (com.my.app/my_content_frame) for fragment a{215e6dc #0 id=0x7f0f0089 main_fragment}
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3403)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3434)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2772)
at android.app.ActivityThread.access$900(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5951)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f0f0089 (com.my.app/my_content_frame) for fragment a{215e6dc #0 id=0x7f0f0089 main_fragment}
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1098)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1286)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:758)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1671)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:388)
at android.support.v4.app.FragmentActivity.onPostResume(FragmentActivity.java:512)
at android.support.v7.app.AppCompatActivity.onPostResume(AppCompatActivity.java:178)
at android.app.Activity.performResume(Activity.java:6430)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3392)
... 11 more
购物清单的堆栈跟踪== null
注意:LoadShoppingListTask
崩溃,因为myShoppingList
成员在任务中为空。这是在onResume()
开头添加测试之前发生的。
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:304)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String[] com.my.app.shoppinglist.j.a(android.content.Context, java.util.ArrayList, java.lang.String, android.util.SparseIntArray, org.json.JSONArray, java.util.ArrayList, boolean)' on a null object reference
at com.my.app.filehandling.ShoppingListFileHandler$LoadShoppingListTask.doInBackground(ShoppingListFileHandler.java:882)
at com.my.app.filehandling.ShoppingListFileHandler$LoadShoppingListTask.doInBackground(ShoppingListFileHandler.java:770)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
... 4 more
来自主要片段中的RecyclerView的堆栈跟踪
注意:绑定数据时,RecyclerView中的不同位置有多个。这个特定的RecyclerView存在于Activity的主要片段中。这些崩溃是我遇到问题的唯一一次。 RecyclerView从活动中的myShoppingList
成员读取其数据。似乎还没有创建视图。
java.lang.NullPointerException: Attempt to read from field 'android.widget.TextView com.my.app.gui.fragments.shoppinglist.k.a' on a null object reference
at com.my.app.gui.fragments.shoppinglist.ShoppingListAdapter.bindRecipeName(ShoppingListAdapter.java:401)
at com.my.app.gui.fragments.shoppinglist.ShoppingListAdapter.onBindViewHolder(ShoppingListAdapter.java:249)
at com.my.app.gui.fragments.shoppinglist.ShoppingListAdapter.onBindViewHolder(ShoppingListAdapter.java:31)
at com.my.app.gui.fragments.shoppinglist.ShoppingListAdapter.access$000(ShoppingListAdapter.java:31)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:5471)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:5504)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4741)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4617)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1994)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1390)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1353)
<snip> Long stack trace inside Android classes...
使用Fragment的堆栈跟踪== null
注意:这是我得到的第一个堆栈跟踪。不幸的是,我没有意识到我必须在此时添加deobscufation文件,因此堆栈跟踪不是那么有用。但很明显,成员myMainFragment
在崩溃时为空。
java.lang.RuntimeException: Unable to resume activity {com.my.app/com.my.app.activities.MyActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.my.app.gui.fragments.c.a.L()' on a null object reference
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3403)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3434)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2772)
at android.app.ActivityThread.access$900(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5951)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.my.app.gui.fragments.c.a.L()' on a null object reference
at com.my.app.activities.MyActivity.t(Unknown Source)
at com.my.app.activities.MyActivity.onResume(Unknown Source)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1255)
at android.app.Activity.performResume(Activity.java:6412)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3392)
... 11 more
我看不出我走错了路。任何提示和评论都表示赞赏。