Android生命周期和空指针问题

bar*_*rry 3 lifecycle android nullpointerexception

我有一个使用SQL数据库的应用程序.这是由SQLiteOpenHelper类封装的.启动启动画面时,它会在DataProvider类上调用init,该类存储SQLiteOpenHelper的受保护静态实例.init只是调用SQLiteOpenHelper的构造函数:

public class UKMPGData extends SQLiteOpenHelper
{
public UKMPGData(Context context, String databaseName)
{
    super(context, databaseName, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db)
{
    //create table and set up triggers etc
}
    @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
    onCreate(db);
}
}

public class UKMPGDataProvider
{
protected static UKMPGData uKMpgData;

public static void init(Context aApplicationContext, String aDatabaseName)
{       
    uKMpgData = new UKMPGData(applicationContext, databaseName);
}

public static void close()
{
    uKMpgData.close();
}
}
Run Code Online (Sandbox Code Playgroud)

然后我又有两个扩展UKMPGDataProvider的类,因此可以访问uKMpgData.这些类从数据库中检索和存储特定类型的数据.例如.

public class VehicleDataProvider extends UKMPGDataProvider
{

    public static Cursor getVehicles()
{
    Cursor cursor = null;

    SQLiteDatabase db = uKMpgData.getReadableDatabase();
    cursor = db.query(VEHICLE_TABLE_NAME, GET_VEHICLES_FROM_CLAUSE, null, null, null, null, ORDER_BY);

    return cursor;
}
//...
}
Run Code Online (Sandbox Code Playgroud)

这一切似乎工作正常,直到我注意到如果应用程序正在运行然后被强制到后台,如果它被放置了几个小时,当应用程序被带回到前台时我会在活动中得到一个空指针调用getVehicles()的类(见上文).事实证明,uKMpgData不再引用对象.

我知道Android可以在必要时杀死进程,但是不明白我的应用程序发生了什么以获取空指针 - 如果我的应用程序的进程被杀死,那么不会启动应用程序的新实例?换句话说,新的SplashScreen将初始化数据库对象,因此没有空指针异常.

我必须遗漏一些东西 - 我的应用程序状态是回收内存(对数据库对象的引用),但是在重新启动时显示最后一个可见活动.

顺便说一下,这个bug现在已经修复了.VehicleDataProvider和其他类似的类不再扩展超类数据提供程序(UKMPGDataProvider),它现在拥有对ukMpgData的私有引用.触摸数据库的所有方法现在都通过UKMPGDataProvider,它将检查null并在必要时重新初始化.

先谢谢你,巴里

ant*_*nyt 8

当Android杀死您的应用程序以回收内存时,您的Application/Activity对象都将被卸载并且将不再存在.但是,Android会保存某些信息,以便在您尝试再次运行应用程序时可以将应用程序还原到该近似状态.

其中一部分包括有关活动堆栈状态的信息(即哪些活动正在运行).正如您所注意到的,Android会将您的应用程序还原到上次运行的Activity,而不是应用程序的开头(启动屏幕).这是一个"功能",我只能假设它是为那些甚至不会注意到应用程序已卸载的用户提供无缝体验的尝试.

在重新创建当前活动之前,Android没有理由重新创建启动画面(即使它仍然存在于活动堆栈中).这种依赖性不受鼓励,并且不是您可以依赖的东西,因为Android会根据需要加载/卸载活动.通常,在先前的活动中初始化的静态是在这种情况下遇到问题的可靠方法.由于没有重新创建启动画面,因此UKMPGDataProvider在您在另一个Activity中使用它之前它不会初始化,因此NullPointerException.

您可以通过两种方式解决此问题.

  1. 初始化使用它的每个Activity 的UKMPGDataProvider内部Activity.onCreate(Bundle).如果正在恢复其中一个活动,则可以保证回调onCreate,因此数据提供程序将始终初始化.

  2. 初始化UKMPGDataProvider内部Application.onCreate().保证在任何Activity启动之前调用它,即使在内存恢复/恢复中也是如此.如果您还没有自定义Application类,则应创建一个子类,然后在其中指向它AndroidManifest.xml供其使用.

顺便说一下,实现Activity.onSaveInstanceState(Bundle)是一种保存与应用程序相关的附加状态的方法,它将在恢复时返回给你Activity.onCreate(Bundle)(它是Bundle参数).它仅用于临时状态,例如在某些用户操作(特别是自定义视图的状态)之后出现的某种视图状态.它不适用于这种情况,因为您可以UKMPGDataProvider轻松生成新的,并且它没有任何链接到上一个会话的状态.