How can I access my SQLite Database in a static way? - java

I was wondering how I could access my SQLite database in my android app in a static way.
I always use this when I want to access the database:
MySQLiteHelper dbHandler = new MySQLiteHelper(this, "PinDB", null, 4);
This is the constructor of MySQLiteHelper:
public MySQLiteHelper(Context context, String name, CursorFactory factory, int version){
super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}
Now, I have to access the database in a static way for a method I want to use. But I have no idea how I could get the context of the activity (this).
I've tried ways like getApplicationContext() etc. but they all don't seem to work.
So, is it possible to change MySQLiteHelper(this,"PinDB", null, 4); into something like this? MySQLiteHelper(MyActivity, "PinDB", null, 4);
If you need any more information, please do ask!
Thanks in advance

I use a Singleton to access the SQLite Database in Android. I think that pattern fits your use case as well.
Session.java (the Singleton class)
public class Session
{
private static DbUtil; // static DBUtil
protected Session() {
//
}
public static Session getInstance() {
if (instance == null) {
instance = new Session();
}
return instance;
}
public void initDBUtil(Context ctx){
util = new DbUtil(ctx);
}
public DbUtil getDbUtil()
{
return util;
}
}
DbUtil.java (the class extending SQLiteOpenHelper)
public class DbUtil extends SQLiteOpenHelper
{
public DbUtil(Context context) {
super(context, NAME_DB, null, 1);
// other init code here...
}
// onCreate and other override
}
In the first onCreate method of your entrance activity just do something like that:
Session.getInstance().initDBUtil(this);
and then you can use the getter in Session to access the DbUtil class with:
Session.getInstance().getUtil(). ... your method here ...

Related

Static variable usage in Java - object never changes

I have been assigned an IT project in which we have to program various different GUI's to do various things. We are also using a database. Let's assume we are accessing an "EntityManager" in a class called "Database":
public class GUI1 {
private Database myDatabase;
public void setDatabase(Database DB){
myDatabase = DB;
}
}
public class GUI2 {
private Database myDatabase;
public void setDatabase(Database DB){
myDatabase = DB;
}
}
public class GUI3 {
private Database myDatabase;
public void setDatabase(Database DB){
myDatabase = DB;
}
}
etc...
Lets say I'm in "GUI1" and I want to switch to "GUI3". After initializing "GUI3" I would have to pass "myDatabase" reference to it via the "setDatabase()" method, but if I want to go back to "GUI1", I would have to pass back the database reference again...
By now I have around 15 GUIs and it get's annoying to copy and paste the same code around when I know it could be replaced easily. In this case, wouldn't it be correct to just use a static reference to whatever I want inside the "Database" class instead of passing around the reference between all my "GUI*" classes?
Create a singleton database object, where everybody access the same object:
public class Database {
private Database(){ // privatize the constructor
// your code here
}
private static Database INSTANCE;
public static Database getInstance() {
if(INSTANCE == null) {
// let's make it thread-safe
synchronized(Database.class) {
if(INSTANCE == null) // may have changed in the mean while
// by other thread
INSTANCE = new Database();
}
}
return INSTANCE;
}
}
EDIT: Even better, from a thread-safe perspective is the enum:
public enum Database {
INSTANCE(); // pair of parenthesis, for constructor
Database() { // constructor
// your code here
}
public static Database getInstance() {
return INSTANCE;// initialization controlled by system
}
public void someMethod(){
// even allows you to add custom methods
}
}

Android - get manifest meta-data out of activity

I want to do something like this
private static final String url;
private static final String pass;
private static final String user;
static {
Bundle metadata = ctx.getPackageManager().getApplicationInfo(ctx.getPackageName(), PackageManager.GET_META_DATA).metaData;
url = (String) metadata.get("JMSQueueURL");
user = (String) metadata.get("JMSQueueUsername");
pass = (String) metadata.get("JMSQueuePassword");
}
So far it was in activity (but not as static), so that I was possible to get package manager, but now i want to move this piece of code to another class which doesn't inherits ContextWrapper (from where we can get package manager). Is it possible somehow? This class is something like util class.
You can pass the Context from the calling method to the method in the Util class and use the context there to get the details you want. This way you can call the method in the Util class from different modules in your application, with different contexts.
// Calling the Util method
Bundle metadata = Util.getMetaData(context);
...
// Inside the Util class
public static Bundle getMetaData(Context context) {
return context.getPackageManager().getApplicationInfo(ctx.getPackageName(), PackageManager.GET_META_DATA).metaData;
}
This allows me to access the metadata from anywhere in my application, without a context:
public class MyAndroidApp extends Application {
private static MyAndroidApp instance;
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static MyAndroidApp getInstance() {
return instance;
}
public static Bundle getMetadata() {
try {
return getInstance()
.getPackageManager()
.getApplicationInfo(getInstance().getPackageName(), PackageManager.GET_META_DATA)
.metaData;
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
}

Android - Random NullPointerException crash reports

Sometimes I'm receiving crash reports from google caused by random NullPointerExceptions (see above). I tried to reproduce those errors but I'm not able to catch them.
Examples of NPE I get :
Caused by: java.lang.NullPointerException
at com.gamequiz.databasemanager.CategoryManager.getAllCategories(CategoryManager.java:28)
Caused by: java.lang.NullPointerException
at com.gamequiz.databasemanager.QuestionManager.getQuestionsFromLevel(QuestionManager.java:30)
at com.gamequiz.databasemanager.QuestionManager.getNumberOfQuestionAnsweredFromLevel(QuestionManager.java:148)
I though that my dbHelper variable is null sometimes but I can't figure out why.
Since I don't know how to resolve that, I post the all steps of my code :
First of all I initialize all the managers in the LaunchActivity :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_launch);
initializeAllManagers();
//some stuff
}
public void initializeAllManagers(){
InitializeAllManagers.init(getApplicationContext());
}
In my InitializeAllManagers class, I set all the managers I need for the lifecycle of the app :
public class InitializeAllManagers {
public static void init(Context context){
DatabaseManager.init(context);
CategoryManager.init(DatabaseManager.getInstance().getHelper());
//and others initializations
}
}
DatabaseManager class (initialization of the dbManager and dbHelper) :
public class DatabaseManager {
private static DatabaseManager instance;
private DatabaseHelper helper;
public static void init(Context ctx) {
if (instance==null) {
instance = new DatabaseManager(ctx);
}
}
public static DatabaseManager getInstance() {
return instance;
}
private DatabaseManager(Context ctx) {
helper = new DatabaseHelper(ctx);
}
public DatabaseHelper getHelper() {
return helper;
}
}
Finally there is an example of one manager :
public class CategoryManager {
private static DatabaseHelper dbHelper;
public static void init(DatabaseHelper dbHelperInstance) {
dbHelper = dbHelperInstance;
}
public static ArrayList <Category> getAllCategories(){
ArrayList <Category> cList = null;
try {
cList = (ArrayList<Category>) dbHelper.getCategoryDao().queryForAll();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return cList;
}
}
So I suspect that my dbHelper variable is null sometimes. Does anyone have an idea about how I can solve this issue ?
EDIT :
NPE mainly refers to this lines :
cList = (ArrayList<Category>) dbHelper.getCategoryDao().queryForAll();
Dao <Question, Long> questionDao = dbHelper.getQuestionDao();
That's why I suspect that dbHelper is null sometimes, and apparently crashes occurs when the app is sleeping for a moment (see feedback above).
Feedback of one user :
So, mainly if I leave the app without exiting it, the app will often
crash when I try to go back to it. Sometimes I just get sent back to
the menu, but mostly just all the way out of the app and I have to
restart it to continue.
I suspect that this happens when the app is minimized for a while and then get re-opened. Android can and will remove Objects from the heap if it feels like it needs the memory. Especially static variables can be removed. Check static variables for null before you access them.
For example in your DatabaseManager class, create the instance in the getInstance() method instead of in init().
public static DatabaseManager getInstance() {
if(instance == null) instance = new DatabaseManager();
return instance;
}
Edit:
Please note that my reasoning in this answer is wrong. Please read all the comments for clarification.

Is it good have a DatabaseManager with all of the functions from all the model objects?

I'working on a db application with ORmlite, my model is like this:
MDL object..
DatabaseTable(tableName = "UserCars")
public class CarMDL
{
#DatabaseField(generatedId = true)
private int _id;
#DatabaseField(columnName = "name")
private String _name;
//................. etc
}
// DB Helper class...
public class DatabaseHelper extends OrmLiteSqliteOpenHelper
{
private Dao<CarMDL,Integer> _carDao = null;
#Override
public void onCreate(SQLiteDatabase database,ConnectionSource connectionSource)
{
try
{
TableUtils.createTable(connectionSource, CarMDL.class);
} catch (SQLException e)
{
throw new RuntimeException(e);
} catch (java.sql.SQLException e)
{
e.printStackTrace();
}
}
public Dao<CarMDL, Integer> getCarDao()
{
if (null == _carDao)
{
try
{
_carDao = getDao(CarMDL.class);
}catch (java.sql.SQLException e)
{
e.printStackTrace();
}
}
return _carDao;
}
}
// DatabaseManager class...
public class DatabaseManager
{
static private DatabaseManager instance;
private DatabaseHelper helper;
static public void init(Context ctx)
{
if (null == instance)
{
instance = new DatabaseManager(ctx);
}
}
static public DatabaseManager getInstance()
{
return instance;
}
private DatabaseManager(Context ctx)
{
helper = new DatabaseHelper(ctx);
}
private DatabaseHelper getHelper()
{
return helper;
}
// All the Dao functions of all MDL objects are in this class, for example:
public List<CarMDL> getAllCars()
{
List<CarMDL> carLists = null;
try
{
carLists = getHelper().getCarDao().queryForAll();
} catch (SQLException e)
{
e.printStackTrace();
}
return carLists;
}
// This is another MDL object..
public List<MarkMDL> getAllMarks()
{
List<MarkMDL> marks = null;
try
{
marks = getHelper().getMarkDao().queryForAll();
} catch (SQLException e)
{
e.printStackTrace();
}
return marks;
}
}
So my question is, is it good have a DatabaseManager with all the functions from all the model objects, like:
listCarById(int id)
listPlaneById(int id)
removeCar(int id)
removePlane(int id)
Etc.....
Updated per Gray's comment.
Be careful with your "singleton" implementation. Your init method should be synchronized to ensure that you don't end up with multiple instances of your DatabaseManager class due to concurrency issues. I would just combine the init and getInstance methods to the following (note the added synchronized keyword):
public static synchronized DatabaseManager getInstance(Context c)
{
if(instance == null)
instance = new DatabaseManager(c);
return instance;
}
For further reading, check out these blog posts about Single SQLite Connection and Android Sqlite locking by Kevin Galligan (one of the contributors to ORMlite).
Update:
To answer your question about how to organize your loading methods like getAllCars, I would first suggest making them static, since they do not depend on anything else besides your method to get your singleton of DatabaseManager, which of course, would also be static. If you have a small number of these types of methods, you could make them all static members of DatabaseManger. If you have many, you could make a helper class for all static methods corresponding to a type.
If you have a method that does depend on the internals of a given instance of CarMDL or MarkMDL (like you need a method to get some associated references), consider making these methods members of the CarMDL or MarkMDL class.
I put all my one-time-per-app work in Application onCreate and I keep a reference of the application instance itself, so I can do many tasks without having to mess with synchronized methods or similar. So let's say we have an Application (remember to add it in the manifest):
public class App extends Application
{
private static App gInstance = null;
// your static globals here
#Override
public void onCreate()
{
// according to documentation onCreate is called before any other method
super.onCreate();
// assign here all your static stuff
gInstance = this;
}
// doesn't need to be synchronized because of the early onCreate
public static App getInstance()
{
return gInstance;
}
}
then your database helper class, Manifest.class is an array of all of your datatype classes:
public class DatabaseHelper extends OrmLiteSqliteOpenHelper
{
// private constructor, singleton pattern, we use
// App context so the class is created on static init
private static DatabaseHelper gHelper = new DatabaseHelper(App.getInstance());
private DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION, R.raw.ormlite_config);
// cache your dao here
for (Class<?> cls: Manifest.classes)
{
try
{
DaoManager.createDao(getConnectionSource(), cls);
} catch (SQLException e)
{
e.printStackTrace();
}
}
}
// if you need the instance, you don't need synchronized because of static init
public static DatabaseHelper getHelper()
{
return gHelper;
}
// lookup from cache
public static <D extends Dao<T, ?>, T> D getTypeDao(Class<T> cls)
{
return DaoManager.lookupDao(gHelper.getConnectionSource(), cls);
}
// we leak this class here since android doesn't provide Application onDestroy
// it's not really a big deal if we need the orm mapping for all application lifetime
// Q: should I keep the instance closeable? the android finalyzer calls somehow close here? I was unable to reproduce, to be sure you can call the super.close() and print a warning
#Override
public void close()
{
throw new RuntimeException("DatabaseHelper Singleton is ethernal");
}
}
addd the context to your DatabaseManager method
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DatabaseManager.init(this.getContext());
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
example android app with ormlite
https://github.com/elberthcabrales/cfeMedicion

How can I get a resource content from a static context?

I want to read strings from an xml file before I do much of anything else like setText on widgets, so how can I do that without an activity object to call getResources() on?
Create a subclass of Application, for instance public class App extends Application {
Set the android:name attribute of your <application> tag in the AndroidManifest.xml to point to your new class, e.g. android:name=".App"
In the onCreate() method of your app instance, save your context (e.g. this) to a static field named mContext and create a static method that returns this field, e.g. getContext():
This is how it should look:
public class App extends Application{
private static Context mContext;
#Override
public void onCreate() {
super.onCreate();
mContext = this;
}
public static Context getContext(){
return mContext;
}
}
Now you can use: App.getContext() whenever you want to get a context, and then getResources() (or App.getContext().getResources()).
For system resources only!
Use
Resources.getSystem().getString(android.R.string.cancel)
You can use them everywhere in your application, even in static constants declarations!
My Kotlin solution is to use a static Application context:
class App : Application() {
companion object {
lateinit var instance: App private set
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
And the Strings class, that I use everywhere:
object Strings {
fun get(#StringRes stringRes: Int, vararg formatArgs: Any = emptyArray()): String {
return App.instance.getString(stringRes, *formatArgs)
}
}
So you can have a clean way of getting resource strings
Strings.get(R.string.some_string)
Strings.get(R.string.some_string_with_arguments, "Some argument")
Please don't delete this answer, let me keep one.
Shortcut
I use App.getRes() instead of App.getContext().getResources() (as #Cristian answered)
It is very simple to use anywhere in your code!
So here is a unique solution by which you can access resources from anywhere like Util class .
(1) Create or Edit your Application class.
import android.app.Application;
import android.content.res.Resources;
public class App extends Application {
private static App mInstance;
private static Resources res;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
res = getResources();
}
public static App getInstance() {
return mInstance;
}
public static Resources getRes() {
return res;
}
}
(2) Add name field to your manifest.xml <application tag. (or Skip this if already there)
<application
android:name=".App"
...
>
...
</application>
Now you are good to go.
Use App.getRes().getString(R.string.some_id) anywhere in code.
There is also another possibilty. I load OpenGl shaders from resources like this:
static private String vertexShaderCode;
static private String fragmentShaderCode;
static {
vertexShaderCode = readResourceAsString("/res/raw/vertex_shader.glsl");
fragmentShaderCode = readResourceAsString("/res/raw/fragment_shader.glsl");
}
private static String readResourceAsString(String path) {
Exception innerException;
Class<? extends FloorPlanRenderer> aClass = FloorPlanRenderer.class;
InputStream inputStream = aClass.getResourceAsStream(path);
byte[] bytes;
try {
bytes = new byte[inputStream.available()];
inputStream.read(bytes);
return new String(bytes);
} catch (IOException e) {
e.printStackTrace();
innerException = e;
}
throw new RuntimeException("Cannot load shader code from resources.", innerException);
}
As you can see, you can access any resource in path /res/...
Change aClass to your class. This also how I load resources in tests (androidTests)
The Singleton:
package com.domain.packagename;
import android.content.Context;
/**
* Created by Versa on 10.09.15.
*/
public class ApplicationContextSingleton {
private static PrefsContextSingleton mInstance;
private Context context;
public static ApplicationContextSingleton getInstance() {
if (mInstance == null) mInstance = getSync();
return mInstance;
}
private static synchronized ApplicationContextSingleton getSync() {
if (mInstance == null) mInstance = new PrefsContextSingleton();
return mInstance;
}
public void initialize(Context context) {
this.context = context;
}
public Context getApplicationContext() {
return context;
}
}
Initialize the Singleton in your Application subclass:
package com.domain.packagename;
import android.app.Application;
/**
* Created by Versa on 25.08.15.
*/
public class mApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
ApplicationContextSingleton.getInstance().initialize(this);
}
}
If I´m not wrong, this gives you a hook to applicationContext everywhere, call it with ApplicationContextSingleton.getInstance.getApplicationContext();
You shouldn´t need to clear this at any point, as when application closes, this goes with it anyway.
Remember to update AndroidManifest.xml to use this Application subclass:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.domain.packagename"
>
<application
android:allowBackup="true"
android:name=".mApplication" <!-- This is the important line -->
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:icon="#drawable/app_icon"
>
Now you should be able to use ApplicationContextSingleton.getInstance().getApplicationContext().getResources() from anywhere, also the very few places where application subclasses can´t.
Please let me know if you see anything wrong here, thank you. :)
Another solution:
If you have a static subclass in a non-static outer class, you can access the resources from within the subclass via static variables in the outer class, which you initialise on creation of the outer class. Like
public class Outerclass {
static String resource1
public onCreate() {
resource1 = getString(R.string.text);
}
public static class Innerclass {
public StringGetter (int num) {
return resource1;
}
}
}
I used it for the getPageTitle(int position) Function of the static FragmentPagerAdapter within my FragmentActivity which is useful because of I8N.
I think, more way is possible.
But sometimes, I using this solution. (full global):
import android.content.Context;
import <your package>.R;
public class XmlVar {
private XmlVar() {
}
private static String _write_success;
public static String write_success() {
return _write_success;
}
public static void Init(Context c) {
_write_success = c.getResources().getString(R.string.write_success);
}
}
//After activity created:
cont = this.getApplicationContext();
XmlVar.Init(cont);
//And use everywhere
XmlVar.write_success();
I load shader for openGL ES from static function.
Remember you must use lower case for your file and directory name, or else the operation will be failed
public class MyGLRenderer implements GLSurfaceView.Renderer {
...
public static int loadShader() {
// Read file as input stream
InputStream inputStream = MyGLRenderer.class.getResourceAsStream("/res/raw/vertex_shader.txt");
// Convert input stream to string
Scanner s = new Scanner(inputStream).useDelimiter("\\A");
String shaderCode = s.hasNext() ? s.next() : "";
}
...
}
I am using API level 27 and found a best solution after struggling for around two days. If you want to read a xml file from a class which doesn't derive from Activity or Application then do the following.
Put the testdata.xml file inside the assets directory.
Write the following code to get the testdata document parsed.
InputStream inputStream = this.getClass().getResourceAsStream("/assets/testdata.xml");
// create a new DocumentBuilderFactory
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// use the factory to create a documentbuilder
DocumentBuilder builder = factory.newDocumentBuilder();
// create a new document from input stream
Document doc = builder.parse(inputStream);
Getting image resouse as InputStream without context:
Class<? extends MyClass> aClass = MyClass.class;
URL r = aClass.getResource("/res/raw/test.png");
URLConnection urlConnection = r.openConnection();
return new BufferedInputStream(urlConnection.getInputStream());
If you need derectory tree for your files, it will also works (assets supports sub-dirs):
URL r = aClass.getResource("/assets/images/base/2.png");
why you dont try
Resources.getSystem().getString(R.string.foo);
Here is an alternative, slightly different, approach that you may try.
You could subclass the Application class like what other solutions mentioned, and store a static reference to an instance of Resources.
Create an application class and initialise the Resources variable in the onCreate method. This will be called when your app starts. We can use WeakReference here to prevent memory leaks that might happen as a result of storing this instance as a static variable(although it is very unlikely to happen)
public class App extends Application {
private static WeakReference<Resources> res;
Since you mentioned that you only want to retrieve strings from the xml resource declaration, there is no need to expose this resource variable to other classes, for encapsulation of the resources instance and to prevent it from leaking out. Hence, you may store the reference as a private variable.
Remember to initialise this variable in onCreate:
#Override
public void onCreate() {
super.onCreate();
res = new WeakReference<>(getResources());
}
We also need to declare the application's android:name as .App(or any other name you set it to) in AndroidManifest.xml under the application tag.
<application android:name=".App"
........... other attributes here ...........
Another way of retrieving the string resource is not by using the Resources instance in other classes(or the Context instance), but to get the App class to get this for you in a static method. This keeps the instance encapsulated/private.
You can use a static method in your App class to retrieve these values(e.g. getStringGlobal, just do not call it getString as it will conflict with the default method)
public static String getStringGlobal(#StringRes int resId) {
if (res != null && res.get() != null) {
return res.get().getString(resId);
} else {
// This should not happen, you should throw an exception here, or you can return a fallback string to ensure the app still runs
}
}
As seen, you can also add error handling in case the instance of Resources is not available(this should not happen, but just in case).
You can then retrieve the string resource by calling
App.getStringGlobal(R.string./*your string resource name*/)
So your App.java:
public class App extends Application {
private static WeakReference<Resources> res;
#Override
public void onCreate() {
super.onCreate();
res = new WeakReference<>(getResources());
}
public static String getStringGlobal(#StringRes int resId) {
if (res != null && res.get() != null) {
return res.get().getString(resId);
} else {
// This should not happen(reference to Resources invalid), you should throw an exception here, or you can return a fallback string to ensure the app still runs
}
}
}
In your class, where you implement the static function, you can call a private\public method from this class. The private\public method can access the getResources.
for example:
public class Text {
public static void setColor(EditText et) {
et.resetColor(); // it works
// ERROR
et.setTextColor(getResources().getColor(R.color.Black)); // ERROR
}
// set the color to be black when reset
private void resetColor() {
setTextColor(getResources().getColor(R.color.Black));
}
}
and from other class\activity, you can call:
Text.setColor('some EditText you initialized');
if you have a context, i mean inside;
public void onReceive(Context context, Intent intent){
}
you can use this code to get resources:
context.getResources().getString(R.string.app_name);
public Static Resources mResources;
#Override
public void onCreate()
{
mResources = getResources();
}

Categories