我有一个使用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();
}
}
然后我又有两个扩展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;
}
//...
}
这一切似乎工作正常,直到我注意到如果应用程序正在运行然后被强制到后台,如果它被放置了几个小时,当应用程序被带回到前台时,我会在活动中得到一个空指针调用getVehicles()的类(见上文).事实证明,uKMpgData不再引用对象.
我知道Android可以在必要时杀死进程,但是不明白我的应用程序发生了什么以获取空指针 – 如果我的应用程序的进程被杀死,那么不会启动应用程序的新实例?换句话说,新的SplashScreen将初始化数据库对象,因此没有空指针异常.
我必须遗漏一些东西 – 我的应用程序状态是回收内存(对数据库对象的引用),但是在重新启动时显示最后一个可见活动.
顺便说一下,这个bug现在已经修复了. VehicleDataProvider和其他类似的类不再扩展超类数据提供程序(UKMPGDataProvider),它现在拥有对ukMpgData的私有引用.触摸数据库的所有方法现在都通过UKMPGDataProvider,它将检查null并在必要时重新初始化.
提前致谢,
巴里
解决方法:
当Android杀死您的应用程序以回收内存时,您的Application / Activity对象都将被卸载并且将不再存在.但是,Android会保存某些信息,以便在您尝试再次运行应用程序时可以将应用程序还原到该近似状态.
其中一部分包括有关活动堆栈状态的信息(即哪些活动正在运行),然后才能销毁.正如您所注意到的,Android会将您的应用程序还原到上次运行的Activity,而不是应用程序的开头(启动屏幕).这是一个“功能”,我只能假设它是为那些甚至不会注意到应用程序已卸载的用户提供无缝体验的尝试.
在重新创建当前活动之前,Android没有理由重新创建启动画面(即使它仍然存在于活动堆栈中).这种依赖性不受鼓励,并且不是您可以依赖的东西,因为Android会根据需要加载/卸载活动.通常,在先前的活动中初始化的静态是在这种情况下遇到问题的可靠方法.由于未重新创建启动屏幕,因此在您在另一个Activity中使用它之前,它不会初始化UKMPGDataProvider,因此会出现NullPointerException.
您可以通过两种方式解决此问题.
>在使用它的每个Activity的Activity.onCreate(Bundle)内初始化UKMPGDataProvider.如果正在恢复其中一个活动,则可以保证对onCreate进行回调,因此将始终初始化数据提供程序.
>在Application.onCreate()内初始化UKMPGDataProvider.保证在任何Activity启动之前调用它,即使在内存恢复/恢复中也是如此.如果您还没有自定义Application类,则应在AndroidManifest.xml中创建一个子类,然后创建point to it以供其使用.
顺便说一句,实现Activity.onSaveInstanceState(Bundle)是一种保存与应用程序相关的附加状态的方法,它将在恢复时在Activity.onCreate(Bundle)(它是Bundle参数)中返回给您.它仅用于临时状态,例如在某些用户操作(特别是自定义视图的状态)之后出现的某种视图状态.它不适用于这种情况,因为您可以轻松生成新的UKMPGDataProvider,并且它没有任何链接到上一个会话的状态.