Android Room Database auto-genereated code does not compile - android

I cannot compile the project because the auto-generated code does not compile.
Here is my code:
I'm using version 2.4.2 of Room
My database class:
RecipeDatabase.java
#Database(entities = {Person.class, Recipe.class}, version = 1)
public abstract class RecipeDatabase extends RoomDatabase {
public abstract PersonDao personDao();
public abstract RecipeDao recipeDao();
}
Entity classes:
Person.java
#Entity(tableName = "people")
public class Person {
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "person_id")
public int id;
public String name;
public Person(String name) {
this.name = name;
}
}
Recipe.java
#Entity(tableName = "recipes")
public class Recipe {
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "recipe_id")
public int id;
public String name;
public FoodType type; //it is an enum
public Recipe(String name, FoodType type) {
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public String getTypeName() {
return type.getName();
}
public int getImageResource() {
return type.getImgResource();
}
}
DAO classes:
PersonDao.java
#Dao
public interface PersonDao {
#Query("SELECT * FROM people")
List<Person> getAll();
#Query("SELECT name FROM people")
List<String> getNames();
}
RecipeDao.java
#Dao
public interface RecipeDao {
#Query("SELECT * FROM recipes")
List<Recipe> getAll();
#Query("SELECT name FROM recipes")
List<String> getNames();
}
And here is the code which does not compile (under java (generated)):
RecipeDatabase_Impl.java
#Override
protected void onCreate(SupportSQLiteDatabase _db) {
if (mCallbacks != null) {
for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {
mCallbacks.get(_i).onCreate(_db);
}
}
}
...
#Override
protected RoomOpenHelper.ValidationResult onValidateSchema(SupportSQLiteDatabase _db) {
final HashMap<String, TableInfo.Column> _columnsPeople = new HashMap<String, TableInfo.Column>(2);
_columnsPeople.put("person_id", new TableInfo.Column("person_id", "INTEGER", true, 1, null, TableInfo.CREATED_FROM_ENTITY));
_columnsPeople.put("name", new TableInfo.Column("name", "TEXT", false, 0, null, TableInfo.CREATED_FROM_ENTITY));
final HashSet<TableInfo.ForeignKey> _foreignKeysPeople = new HashSet<TableInfo.ForeignKey>(0);
final HashSet<TableInfo.Index> _indicesPeople = new HashSet<TableInfo.Index>(0);
final TableInfo _infoPeople = new TableInfo("people", _columnsPeople, _foreignKeysPeople, _indicesPeople);
final TableInfo _existingPeople = TableInfo.read(_db, "people");
if (! _infoPeople.equals(_existingPeople)) {
return new RoomOpenHelper.ValidationResult(false, "people(com.szabolcst.recipes.model.Person).\n"
+ " Expected:\n" + _infoPeople + "\n"
+ " Found:\n" + _existingPeople);
}
final HashMap<String, TableInfo.Column> _columnsRecipes = new HashMap<String, TableInfo.Column>(3);
_columnsRecipes.put("recipe_id", new TableInfo.Column("recipe_id", "INTEGER", true, 1, null, TableInfo.CREATED_FROM_ENTITY));
_columnsRecipes.put("name", new TableInfo.Column("name", "TEXT", false, 0, null, TableInfo.CREATED_FROM_ENTITY));
_columnsRecipes.put("type", new TableInfo.Column("type", "TEXT", false, 0, null, TableInfo.CREATED_FROM_ENTITY));
final HashSet<TableInfo.ForeignKey> _foreignKeysRecipes = new HashSet<TableInfo.ForeignKey>(0);
final HashSet<TableInfo.Index> _indicesRecipes = new HashSet<TableInfo.Index>(0);
final TableInfo _infoRecipes = new TableInfo("recipes", _columnsRecipes, _foreignKeysRecipes, _indicesRecipes);
final TableInfo _existingRecipes = TableInfo.read(_db, "recipes");
if (! _infoRecipes.equals(_existingRecipes)) {
return new RoomOpenHelper.ValidationResult(false, "recipes(com.szabolcst.recipes.model.Recipe).\n"
+ " Expected:\n" + _infoRecipes + "\n"
+ " Found:\n" + _existingRecipes);
}
return new RoomOpenHelper.ValidationResult(true, null);
}
}, "1c493a2b22e38e23def00f0336257ee2", "6829c4aff16c254527acbdc5d6cecc85");
final SupportSQLiteOpenHelper.Configuration _sqliteConfig = SupportSQLiteOpenHelper.Configuration.builder(configuration.context)
.name(configuration.name)
.callback(_openCallback)
.build();
final SupportSQLiteOpenHelper _helper = configuration.sqliteOpenHelperFactory.create(_sqliteConfig);
return _helper;
}
In both methods the problem is with the access modifer (protected) and the error goes: 'attempting to assign weaker access privileges; was public'
The methods that these override are:
RoomOpenHelper.kt
#RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
abstract class Delegate(#JvmField val version: Int) {
abstract fun dropAllTables(database: SupportSQLiteDatabase)
abstract fun createAllTables(database: SupportSQLiteDatabase)
abstract fun onOpen(database: SupportSQLiteDatabase)
abstract fun onCreate(database: SupportSQLiteDatabase)
...
#Suppress("DEPRECATION")
open fun onValidateSchema(db: SupportSQLiteDatabase): ValidationResult {
validateMigration(db)
return ValidationResult(true, null)
}
The full errors:
error: onCreate(SupportSQLiteDatabase) in <anonymous com.szabolcst.recipes.persistance.RecipeDatabase_Impl$1> cannot override onCreate(SupportSQLiteDatabase) in Delegate
protected void onCreate(SupportSQLiteDatabase _db) {
^
attempting to assign weaker access privileges; was public
error: onValidateSchema(SupportSQLiteDatabase) in <anonymous com.szabolcst.recipes.persistance.RecipeDatabase_Impl$1> cannot override onValidateSchema(SupportSQLiteDatabase) in Delegate
protected RoomOpenHelper.ValidationResult onValidateSchema(SupportSQLiteDatabase _db) {
^
attempting to assign weaker access privileges; was public
Naturally editing anything in the generated files does not help, and I can't find anything like this on any forums

Changing implementation "androidx.room:room-runtime:2.4.2" back to implementation "androidx.room:room-runtime:2.3.0" seemed to help as now RoomOpenHelper.java is used instead of the kotlin version and in the java version the access modifer is protected.

Related

How can I reference variables of generic types?

I am trying to implement a "base DAO" interface for the Room library so as to avoid boilerplate code:
BaseEntity.kt
interface BaseEntity {
val entityName: String
}
Note.kt
#Entity
class Note : BaseEntity {
override val entityName: String = "note"
...
}
BaseDao.kt
interface BaseDao<T : BaseEntity> {
#Query("SELECT * FROM ${T.entityName}")
fun selectAll(): List<T>
...
}
NoteDao.kt
#Dao
interface NoteDao : BaseDao<Note> {
...
}
However, the expression ${T.entityName} is invalid. Is there a way to do this?
I don't believe that you can implement a "base DAO" interface. The reason is that Room creates each DAO implementation at compile time. And hence why you get the message An annotation argument must be a compile time-constant.
Room needs to know, from the annotation (for example), which table columns to map to which variables and the methods used to perform the mapping so that the underlying code can be generated.
As an example if the Entity and the Dao were :-
#Entity
class Note {
#PrimaryKey
var entityName: String = ""
}
and
#Dao
interface BaseDao {
#Query("SELECT * FROM Note")
fun selectAll(): List<Note>
}
Then the underlying generated java would be :-
public final class BaseDao_Impl implements BaseDao {
private final RoomDatabase __db;
public BaseDao_Impl(RoomDatabase __db) {
this.__db = __db;
}
#Override
public List<Note> selectAll() {
final String _sql = "SELECT * FROM Note";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
__db.assertNotSuspendingTransaction();
final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
try {
final int _cursorIndexOfEntityName = CursorUtil.getColumnIndexOrThrow(_cursor, "entityName");
final List<Note> _result = new ArrayList<Note>(_cursor.getCount());
while(_cursor.moveToNext()) {
final Note _item;
_item = new Note();
final String _tmpEntityName;
_tmpEntityName = _cursor.getString(_cursorIndexOfEntityName);
_item.setEntityName(_tmpEntityName);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
}

how can I add rows to DB on android only when DB is created? (using room)

I have category class:
#Entity(tableName = "Categories",indices = {#Index(value = {"id"},
unique = true)})
public class Category implements Serializable {
public Category(String name,int icon,int color)
{
_name= name;
_icon = icon;
_color = color;
}
#PrimaryKey(autoGenerate = true)
public int id;
#ColumnInfo(name = "name")
public String _name;
#ColumnInfo(name = "icon")
public int _icon;
#ColumnInfo(name = "color")
public int _color;
public String get_name() {return _name;}
public int getColor() {
return _color;
}
public int getIcon() {
return _icon;
}
}
and I would like to create constant rows only when DB is newly created and not each time the application is loading.
what I did till now is:
protected CategorySingletone() {
// Exists only to defeat instantiation.
AppDatabase db = AppDatabase.getAppDatabase(MainActivity.get().getApplicationContext());
if (db.categoryDao().countCategories()==0) {
_categoryList = new ArrayList<>();
_categoryList.add(new Category("Cars", R.drawable.couch, 3));
_categoryList.add(new Category("Tech", R.drawable.phone, 3));
_categoryList.add(new Category("Home", R.drawable.book_1, 3));
_categoryList.add(new Category("Leisure", R.drawable.book_1, 3));
_categoryList.add(new Category("Motors", R.drawable.book_4, 3));
_categoryList.add(new Category("Fashion", R.drawable.book_5, 3));
for (Iterator<Category> i = _categoryList.iterator(); i.hasNext();) {
Category item = i.next();
db.categoryDao().insertAll(item);
}
}
while I am checking if rows exists.
is there a better way?
A more efficient way would be to use the DatabaseUtils queryNumEntries method.
e.g.
if (DatabaseUtils.queryNumEntries(db,"Categories") == 0) {
.......
}

Query a view doesn't works with DBFlow

I'm using DBflow to query an SQLite database containing several tables. Since my query contains a lot of joins it's kind of difficult to read using the DBflow join :
SQLite.select()
.from(Plant.class).as("p0")
.innerJoin(Definition.class).as("d0")
.on(Plant_Table.definitionId.withTable(NameAlias.builder("p0").build()).eq(Definition_Table.definitionId.withTable(NameAlias.builder("d0").build())))
.innerJoin(Picture.class).as("pi0")
.on(Plant_Table.pictureId.withTable(NameAlias.builder("p0").build()).eq(Picture_Table.pictureid.withTable(NameAlias.builder("pi0").build())))
.innerJoin(SpaceAssociation.class)
.on(Plant_Table.pictureId.withTable(NameAlias.builder("p0").build()).eq(SpaceAssociation_Table.plantId1))
.innerJoin(Plant.class).as("p1")
.on(SpaceAssociation_Table.plantId2.eq(Plant_Table.plantId.withTable(NameAlias.builder("p1").build())))
.innerJoin(Definition.class).as("d1")
.on(Plant_Table.definitionId.withTable(NameAlias.builder("p1").build()).eq(Definition_Table.definitionId.withTable(NameAlias.builder("d1").build())))
.innerJoin(Picture.class).as("pi1")
.on(Plant_Table.pictureId.withTable(NameAlias.builder("p1").build()).eq(Picture_Table.pictureid.withTable(NameAlias.builder("pi1").build())))
.innerJoin(Flag.class)
.on(SpaceAssociation_Table.flagId.eq(Flag_Table.flagId))
.innerJoin(FlagDefinition.class)
.on(Flag_Table.flagDefinitionId.eq(FlagDefinition_Table.flagDefinitionId));
So I decided it would be a better idea to create a SQL view in my database and query this view :
SQLite.select()
.from(PlantsAssociations.class)
.queryList();
Far more readable ! The problem is that I'm getting this error
database.sqlite.SQLiteException: no such table: PlantsAssociations (code 1): , while compiling: SELECT * FROM PlantsAssociations
If I copy and paste this generated query and execute it directly in SQLite console on my database it works...
I check the official documentation, it says "Declared like tables" :
Views: Declared like tables, Views (Virtual Tables) are supported.
So I declared my view exactly like a table :
#Table(database = PlantsDatabase.class)
public class PlantsAssociations extends BaseModel {
#PrimaryKey
#Column(name = "p0_plant_id")
private int p0PlantId;
#Column(name = "p0_definition")
private String p0Definition;
#Column(name = "p0_picture")
private String p0Picture;
#Column(name = "p1_plant_id")
private int p1PlantId;
#Column(name = "p1_definition")
private String p1Definition;
#Column(name = "p1_picture")
private String p1Picture;
#Column(name = "flag_id")
private int flagId;
#Column(name = "flag_definition")
private String flagDefinition;
public PlantsAssociations() { }
public PlantsAssociations(int p0PlantId, String p0Definition, String p0Picture, int p1PlantId, String p1Definition, String p1Picture, int flagId, String flagDefinition) {
this.p0PlantId = p0PlantId;
this.p0Definition = p0Definition;
this.p0Picture = p0Picture;
this.p1PlantId = p1PlantId;
this.p1Definition = p1Definition;
this.p1Picture = p1Picture;
this.flagId = flagId;
this.flagDefinition = flagDefinition;
}
public int getP0PlantId() {
return p0PlantId;
}
public void setP0PlantId(int p0PlantId) {
this.p0PlantId = p0PlantId;
}
public String getP0Definition() {
return p0Definition;
}
public void setP0Definition(String p0Definition) {
this.p0Definition = p0Definition;
}
public String getP0Picture() {
return p0Picture;
}
public void setP0Picture(String p0Picture) {
this.p0Picture = p0Picture;
}
public int getP1PlantId() {
return p1PlantId;
}
public void setP1PlantId(int p1PlantId) {
this.p1PlantId = p1PlantId;
}
public String getP1Definition() {
return p1Definition;
}
public void setP1Definition(String p1Definition) {
this.p1Definition = p1Definition;
}
public String getP1Picture() {
return p1Picture;
}
public void setP1Picture(String p1Picture) {
this.p1Picture = p1Picture;
}
public int getFlagId() {
return flagId;
}
public void setFlagId(int flagId) {
this.flagId = flagId;
}
public String getFlagDefinition() {
return flagDefinition;
}
public void setFlagDefinition(String flagDefinition) {
this.flagDefinition = flagDefinition;
}
}
But as said before it looks like DBflow generate the right query but there is something wrong by finding the view on SQLite side....
So I checked the official SQLite documentation and it looks like I did it right :
CREATE VIEW PlantsAssociations
as
select p0.plantid as p0_plant_id,
d0.definition as p0_definition,
pi0.picture as p0_picture,
p1.plantid as p1_plant_id,
d1.definition as p1_definition,
pi1.picture as p1_picture,
flag.flagId as flag_id,
flagDefinition.definition as flag_definition
from plant p0
inner join definition d0
on p0.definitionId = d0.definitionId
inner join picture pi0
on p0.pictureId = pi0.pictureId
inner join spaceAssociation
on p0.plantId = spaceAssociation.plantId1
inner join plant p1
on spaceAssociation.plantId2 = p1.plantid
inner join definition d1
on p1.definitionid = d1.definitionid
inner join flag
on spaceAssociation.flagId = flag.flagId
inner join flagDefinition
on flag.flagDefinitionId = flagDefinition.flagDefinitionId
inner join picture pi1
on p1.pictureid = pi1.pictureid
where d0.definition != d1.definition
Did i missed something ?
[EDIT]
I just increased the database version number but now the query just returns me an empty list...
Uninstalled the app then ./gradelw clean and Reintall the app.
it works...

How to get foreign DatabaseField automatically with query?

I'm using ORMLite (v4.48) with my Android app. I have the table "Contact" which can contain multiple "Email" (ForeignCollectionField) and one "Personal" (DatabaseField) object. When I get the Contact object from the database I would like to automatically get (or lazy load) the Personal object which has the same Contact ID.
It already automatically gets the Email objects which I can access. But for some reason the Personal object is always "null" even though there is an entry in the Personal table.
Here are my classes:
#DatabaseTable(tableName = "Contact", daoClass = ContactDao.class)
public class Contact {
#DatabaseField(generatedId = true, columnName = PersistentObject.ID)
int id;
#DatabaseField(index = true)
String contactName;
#ForeignCollectionField(eager = false)
ForeignCollection<Email> emails;
#DatabaseField(foreign = true)
public Personal personal;
public ForeignCollection<Email> getEmails() {
return emails;
}
public void setEmails(ForeignCollection<Email> emails) {
this.emails = emails;
}
public Personal getPersonal() {
return personal;
}
public void setPersonal(Personal personal) {
this.personal = personal;
}
...
}
And
#DatabaseTable(tableName = "Email", daoClass = EmailDao.class)
public class Email {
#DatabaseField(generatedId = true, columnName = PersistentObject.ID)
int id;
#DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = PersistentObject.CONTACT_ID_FIELD_NAME) // contact_id
Contact contact;
#DatabaseField
String emailType;
#DatabaseField(canBeNull = false)
String email;
public Email() {
}
public Email(int id, Contact Contact, String emailType, String email) {
this.id = id;
this.contact = contact;
this.emailType = emailType;
this.email = email;
}
public int getId() {
return id;
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public String getEmailType() {
return emailType;
}
public void setEmailType(String emailType) {
this.emailType = emailType;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
...
}
and
#DatabaseTable(tableName = "Personal", daoClass = PersonalDao.class)
public class Personal {
#DatabaseField(generatedId = true, columnName = PersistentObject.ID)
int id;
#DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = PersistentObject.CONTACT_ID_FIELD_NAME)
Contact contact;
#DatabaseField
int age;
#DatabaseField
int weight; // in grams
#DatabaseField
int height; // in cm
public Personal() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
I'm getting the data from the database like this:
QueryBuilder<Contact, Integer> queryBuilder = mContactDao.queryBuilder();
queryBuilder.orderBy("lastViewed", false);
queryBuilder.limit(limit);
PreparedQuery<Contact> preparedQuery = queryBuilder.prepare();
List<Contact> contactList = mContactDao.query(preparedQuery);
that all works well so far.
Then further down the code I can access the Email objects like this:
ForeignCollection<Email> emails = contact.getEmails();
Iterator<Email> iter = emails.iterator();
while (iter.hasNext()) {
Email iAddress = iter.next();
Log.d(TAG, "EMAIL: " + iAddress.getEmail());
Log.d(TAG, "EMAIL TYPE: " + iAddress.getEmailType());
}
Which also works perfectly. Only if I want to access the Personal object I always get NULL.
Personal personal = contact.getPersonal(); // is always NULL
I can't figure out why that is. Do I manually need to add a JOIN in the query builder? I thought it would also lazily load the data once I access it with getPersonal() like it does with getEmails()?
You did not show how entity instances are created, but i assume Personal is created after Contact has been inserted. If that is a case, then after inserting Personal you should do contact.setPersonal(personal), and contactDao.update(contact) - that way personal_id will be stored in contact row

Where to create business logic objects and maintain state?

My application relies on a core module of Android independent classes to carry out business logic. These objects need to be available to all parts of the app and also needs to maintain its state throughout the application.
I have been instantiating these objects in an Application subclass and using them throughout my activities and services. But when Android decides to kill my app to free up memory, those business logic objects are also killed and lose their state.
What is the best strategy for stateful business object models in an Android application?
Perfect solution for this is to use persistence storage. What I follow is bit complex but very useful.
It is divided in three parts :
SQLite Database
API Helper
Singleton Class ( Data Helper )
and following steps :
Retrieve all data from db to single instance classes.
Whenever I need to update it then update in class.
Dump it in database at some particular event. (like button click or back press).
By this way you have all of your data intact and easily available through out the app
Database : Not going to elaborate it. It can be any persistence storage like db or preference.
API Helper : Sample api helper class. It can be any thing depending on your storage.
public class AppsApi {
private static AppsApi appInstance;
private Context mContext;
public static AppsApi getInstance(Context context) {
if (appInstance == null)
appInstance = new AppsApi(context);
return appInstance;
}
public AppsApi(Context context) {
this.mContext = context;
}
public static String PROJECTION[];
static {
String[] arrayOfString = new String[5];
arrayOfString[0] = AppsTable.COLUMN_ID;
arrayOfString[1] = AppsTable.COLUMN_APP_NAME;
arrayOfString[2] = AppsTable.COLUMN_APP_PACKAGE_NAME;
arrayOfString[3] = AppsTable.COLUMN_APP_ACTIVITY_NAME;
arrayOfString[4] = AppsTable.COLUMN_IS_FROM_DASHBOARD;
PROJECTION = arrayOfString;
}
public int insertApp(ContentValues app) {
Uri uri = mContext.getContentResolver().insert(
DashDroidContentProvider.CONTENT_URI_APP, app);
System.out.println("APP Added URI :: " + uri);
return Integer.parseInt(uri.getLastPathSegment());
}
public Cursor getAllApps() {
return mContext.getContentResolver().query(
DashDroidContentProvider.CONTENT_URI_APP, AppsApi.PROJECTION,
null, null, null);
}
public Cursor getAllApp(boolean isFromDashBoard) {
int is = isFromDashBoard ? 1 : 0;
return mContext.getContentResolver().query(
DashDroidContentProvider.CONTENT_URI_APP, AppsApi.PROJECTION,
AppsTable.COLUMN_IS_FROM_DASHBOARD + " LIKE ?",
new String[] { is + "" }, null);
}
public void deleteApp(int id) {
mContext.getContentResolver().delete(
DashDroidContentProvider.CONTENT_URI_APP,
AppsTable.COLUMN_ID + " = ?", new String[] { id + "" });
}
public void deleteApp(String packageName) {
mContext.getContentResolver().delete(
DashDroidContentProvider.CONTENT_URI_APP,
AppsTable.COLUMN_APP_PACKAGE_NAME + " LIKE ?",
new String[] { packageName + "" });
}
public void updateApp(ContentValues app, int id) {
int uri = mContext.getContentResolver().update(
DashDroidContentProvider.CONTENT_URI_APP, app, "_id=?",
new String[] { id + "" });
System.out.println("App Updated URI ::" + uri);
}
public void clear() {
mContext.getContentResolver().delete(
DashDroidContentProvider.CONTENT_URI_APP, null, null);
}
public int count() {
return ((Cursor) mContext.getContentResolver().query(
DashDroidContentProvider.CONTENT_URI_APP,
new String[] { AppsTable.COLUMN_ID }, null, null, null))
.getCount();
}
public Cursor filterApp(String selection, String[] selectionArgs) {
return mContext.getContentResolver().query(
DashDroidContentProvider.CONTENT_URI_APP, AppsApi.PROJECTION,
selection, selectionArgs, null);
}
public int insertBulkApps(ContentValues[] apps) {
int noOfRecordInserted = mContext.getContentResolver().bulkInsert(
DashDroidContentProvider.CONTENT_URI_APP, apps);
System.out.println("Inserted Record Count :: " + noOfRecordInserted);
return noOfRecordInserted;
}
}
Data Helper : It is a single instance class. Provides you with data through out the app. It is huge but simple.
public class AppsHelper {
public static final int TYPE_SAVE = 0;
public static final int TYPE_GET = 1;
public static final int TYPE_UPDATE = 2;
private AppsData[] appsDashBoard;
private AppsData[] appsMoreApps;
private AppsApi appsProvider;
private OnDataBaseUpdateListener mListener;
private static AppsHelper mHelper;
public AppsHelper(Context context) {
appsProvider = AppsApi.getInstance(context);
initData();
if (appsProvider.count() == 0) {
new saveDataTask().execute();
} else {
updateAppsFromDatabase();
}
}
public static AppsHelper getInstance(Context context) {
if (mHelper == null)
mHelper = new AppsHelper(context);
return mHelper;
}
private void initData() {
appsDashBoard = new AppsData[DashDroidConstants.NO_OF_DASH_BOARD_APPS];
appsMoreApps = new AppsData[DashDroidConstants.NO_OF_MORE_APPS];
for (int i = 0; i < appsDashBoard.length; i++) {
appsDashBoard[i] = new AppsData(i, "null", "null", "null");
}
for (int i = appsDashBoard.length; i < (appsMoreApps.length + appsDashBoard.length); i++) {
appsMoreApps[i - appsDashBoard.length] = new AppsData(i, "null",
"null", "null");
}
}
public void updateMoreApp(String appName, String activityName,
String appPackageName, int index) {
appsMoreApps[index].setData(appName, activityName, appPackageName);
new updateDataTask(false, index).execute();
}
public void updateMoreApp(String appName, String activityName,
String appPackageName, int index, OnDataBaseUpdateListener listener) {
appsMoreApps[index].setData(appName, activityName, appPackageName);
this.mListener = listener;
new updateDataTask(false, index).execute();
}
public void updateDashBoardApp(String appName, String activityName,
String appPackageName, int index) {
appsDashBoard[index].setData(appName, activityName, appPackageName);
new updateDataTask(true, index).execute();
}
public void updateDashBoardApp(String appName, String activityName,
String appPackageName, int index, OnDataBaseUpdateListener listener) {
appsDashBoard[index].setData(appName, activityName, appPackageName);
this.mListener = listener;
new updateDataTask(true, index).execute();
}
public void updateAppsFromDatabase() {
new getDataTask().execute();
}
public AppsData[] getDashBoardApps() {
return appsDashBoard;
}
public AppsData[] getMoreApps() {
return appsMoreApps;
}
private void updateAppInDatabase(boolean isDashBoardApp, int index) {
ContentValues cv = new ContentValues();
cv = new ContentValues();
if (isDashBoardApp) {
cv.put(AppsTable.COLUMN_APP_PACKAGE_NAME,
appsDashBoard[index].getPackageName());
cv.put(AppsTable.COLUMN_APP_ACTIVITY_NAME,
appsDashBoard[index].getActivityName());
cv.put(AppsTable.COLUMN_APP_NAME, appsDashBoard[index].getAppName());
} else {
cv.put(AppsTable.COLUMN_APP_PACKAGE_NAME,
appsMoreApps[index].getPackageName());
cv.put(AppsTable.COLUMN_APP_ACTIVITY_NAME,
appsMoreApps[index].getActivityName());
cv.put(AppsTable.COLUMN_APP_NAME, appsMoreApps[index].getAppName());
}
int dbIndex = isDashBoardApp ? index : index + appsDashBoard.length;
appsProvider.updateApp(cv, dbIndex);
}
private int saveDataInDatabase() {
ContentValues[] cv = new ContentValues[appsDashBoard.length
+ appsMoreApps.length];
for (int i = 0; i < appsDashBoard.length; i++) {
cv[i] = new ContentValues();
cv[i].put(AppsTable.COLUMN_ID, appsDashBoard[i].getId());
cv[i].put(AppsTable.COLUMN_APP_PACKAGE_NAME,
appsDashBoard[i].getPackageName());
cv[i].put(AppsTable.COLUMN_APP_ACTIVITY_NAME,
appsDashBoard[i].getActivityName());
cv[i].put(AppsTable.COLUMN_APP_NAME, appsDashBoard[i].getAppName());
cv[i].put(AppsTable.COLUMN_IS_FROM_DASHBOARD, "1");
}
for (int i = appsDashBoard.length; i < (appsMoreApps.length + appsDashBoard.length); i++) {
cv[i] = new ContentValues();
cv[i].put(AppsTable.COLUMN_ID, appsMoreApps[i
- appsDashBoard.length].getId());
cv[i].put(AppsTable.COLUMN_APP_PACKAGE_NAME, appsMoreApps[i
- appsDashBoard.length].getPackageName());
cv[i].put(AppsTable.COLUMN_APP_ACTIVITY_NAME, appsMoreApps[i
- appsDashBoard.length].getActivityName());
cv[i].put(AppsTable.COLUMN_APP_NAME, appsMoreApps[i
- appsDashBoard.length].getAppName());
cv[i].put(AppsTable.COLUMN_IS_FROM_DASHBOARD, "0");
}
return appsProvider.insertBulkApps(cv);
}
private void getDataFromDatabase() {
Cursor appCursor = appsProvider.getAllApps();
appCursor.moveToFirst();
for (int i = 0; i < appsDashBoard.length; i++) {
appsDashBoard[i]
.setData(
appCursor.getString(appCursor
.getColumnIndex(AppsTable.COLUMN_APP_NAME)),
appCursor.getString(appCursor
.getColumnIndex(AppsTable.COLUMN_APP_ACTIVITY_NAME)),
appCursor.getString(appCursor
.getColumnIndex(AppsTable.COLUMN_APP_PACKAGE_NAME)));
appCursor.moveToNext();
}
for (int i = 0; i < appsMoreApps.length; i++) {
appsMoreApps[i]
.setData(
appCursor.getString(appCursor
.getColumnIndex(AppsTable.COLUMN_APP_NAME)),
appCursor.getString(appCursor
.getColumnIndex(AppsTable.COLUMN_APP_ACTIVITY_NAME)),
appCursor.getString(appCursor
.getColumnIndex(AppsTable.COLUMN_APP_PACKAGE_NAME)));
appCursor.moveToNext();
}
}
private class saveDataTask extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... params) {
return saveDataInDatabase();
}
#Override
protected void onPostExecute(Integer result) {
if (mListener != null)
mListener.onDataUpdate(TYPE_SAVE);
super.onPostExecute(result);
}
}
private class getDataTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
getDataFromDatabase();
return null;
}
#Override
protected void onPostExecute(Void result) {
if (mListener != null)
mListener.onDataUpdate(TYPE_GET);
super.onPostExecute(result);
}
}
private class updateDataTask extends AsyncTask<Void, Void, Void> {
boolean isFromDashBoard;
int index;
public updateDataTask(boolean isFromDashBoard, int index) {
this.isFromDashBoard = isFromDashBoard;
this.index = index;
}
#Override
protected Void doInBackground(Void... params) {
updateAppInDatabase(isFromDashBoard, index);
return null;
}
#Override
protected void onPostExecute(Void result) {
if (mListener != null)
mListener.onDataUpdate(TYPE_UPDATE);
super.onPostExecute(result);
}
}
public static class AppsData {
int id;
String appName;
String activityName;
String packageName;
public AppsData(int id, String appName, String activityName,
String packageName) {
this.id = id;
this.appName = appName;
this.activityName = activityName;
this.packageName = packageName;
}
public void setData(String appName, String activityName,
String packageName) {
this.appName = appName;
this.activityName = activityName;
this.packageName = packageName;
}
public int getId() {
return id;
}
public String getAppName() {
return appName;
}
public String getPackageName() {
return packageName;
}
public String getActivityName() {
return activityName;
}
}
public interface OnDataBaseUpdateListener {
public void onDataUpdate(int updateType);
}
}
It helps you in creating a more structured code and always available data, just need to call AppsHelper.getInstance(context) and boom!!!. :)
if you want to save them when user closes the application , you must save them in shared preferences or database or in a file in phone memory!
and for inside application, you can simply define them in a class that extends from Serializable or Parcelable and pass them between activities/fragments/etc

Categories

Resources