I am attempting to implement Sqlcipher for android. I am using this for multiple activities and as such am extending SQLiteOpenHelper {}.
However I am
I am aware that the OnCreate override method is not called until the database is accessed for the first time.
My oncreate method looks like
#Override
public void onCreate(SQLiteDatabase db) {
SQLiteDatabase.loadLibs(context);
File databaseFile = context.getDatabasePath("SyncableDiabetesDatabase.db");
databaseFile.mkdirs();
databaseFile.delete();
mDataBase = SQLiteDatabase.openOrCreateDatabase(databaseFile,SuperKey, null);
I am attempting to get the OnCreate Method to call this method by calling this.getWritableDatabase(SuperKey); However when I run this command i receive the error
net.sqlcipher.database.SQLiteException: attempt to write a readonly database: PRAGMA user_version = 1
I'm not exactly sure how this is possible since the command is for a writeable DB
I know sqlcipher is correctly installed, as I can put the DB creation code above outside of OnCreate and the data is stored correctly. However the file is overridden each time the activity is called than, hence why I am moving it to OnCreate which is only called once when I create the tables.
Any insight here would be more than welcome.
I can provide any additional code snippits if needed.
Thank you
You do not need to call SQLiteDatabase.openOrCreateDatabase within the onCreate method of the SQLiteOpenHelper, the database instance is already provided as a parameter to the function. An example of using the SQLiteOpenHelper can be found here.
Related
I have requirement like i need to deleted selected file information if anybody selected wrong file, but after call delete() method its deleted from gallery also,
my question is how can remove selected file URI information i dont want to delete selected file form gallery, any help?
Working with Android Architecture Components, such as: View Model, LiveData, etc. I would like to suggest you to follow Official Guide from Android.
When using Android Architecture Components to call a API request, how I try to achieve my goal is as follow:
Create one Repo class, in that class, initialize the Retrofit Interface(if using Retrofit). Create a function that calls the required API, handle request response and returns a Live Data. Make extra functions for the parameter to be passed with URL.
Create one View Model class, in that class, initialize above Repo class. Create a function that calls repo class function which returns Live Data and this function also returns LiveData. Make extra functions for the parameter to be passed to Repo for adding with URL.
In your View class (Activity/Fragment), initialize View Model class and pass those parameters which are required URL params. Call the View Model function, which returns Live Data and observe that in your View class.
You will get data in your View Class when any change appears in Live Data.
Above is a simple practice, but it can be made good by making responses generic according to your requirement.
You can create public function in VM and pass desired paramas to it and then invoke desired URL from repo .
Refer example
https://github.com/googlesamples/android-architecture-components/blob/master/BasicSample/app/src/main/java/com/example/android/persistence/viewmodel/ProductListViewModel.java
you can call some public method from viewmodel and then pass params to it.somehow like this
viewmodel
class UserViewmodel: ViewModel() {
fun callApi(userId: String) : Any {
// Your method definition
return result
}
}
and in activity / fragment call method via viewmodel instance
class UserActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
val viewModel = ViewModelProviders.of(this).get(UserViewmodel::class.java)
val result = viewModel.callApi("userId")
}
}
I am using three activities which are opened at the same time. All activities are retreive data from sqlite. I don't close or re open my connection when i am going from activity a->b or from b->c.
I just dispose my db when activity is destroying.
Activity A
SqliteConnection db;
OnCreate method
db = new SqliteConnection(mypath);
OnDestroy
db.Dispose();
db=null;
Onbuttonclick
startActivity(new Intent(this, ActivityB));
Same code is running when i am going from activity b->c.
Inside the same activity i use sqlite plenty of times.
Is this a good practice? Should i dispose my connection immediatelly after a use? Or should i close my connection on pause and reopen on resume? Or can i pass the same opened connection to the next activity? Which is the best approach?
Question modifieded
class databaseHelper
{
private static SqliteConnection db;
public static SqliteConnection openDatabase(Context context)
{
if(db==null)
db = new SqliteConnection(mypath);
return db;
}
}
And inside my activity on create
databaseHelper.openDatabase(this).myquery....
I don`t roll with Java nor xamarin. Here is a Kotlin code, it is pretty self-explanatory.
class DatabaseHelper { //Public class
companion object { ///This is equiavalent to java static.
private var instance: YourDatabase? = null
fun getDbInstance(context: Context): YourDatabase? //This functions returns the initialized DB instance.
{
if(instance == null)
instance = YourDatabase(context) // initializing the DB only one time
return instance
}
}
}
Just create a public class and name it for example "DatabaseHelper". Inside the class, create one static variable of your database type. Create a public function that returns the static variable. Inside the function, first, check if the static instance is null and if it is null, then initialize it with your database instance. This way, when you need to use your database instance, just, access the static function, provide it with the context and it will return you the initialized database instance.
In Kotlin
DatabaseHelper.getDbInstance(this).yourDbFunction()
UPDATE
Since this answer took off, I would like to suggest improvements to my previous solution. Instead of passing a context of activity to initialize the database, use application context. If you give an activity context to the static database instance, a memory leak will occur because the database instance holds a strong reference to the activity and the activity will NOT be eligible for garbage collection.
Proper usage:
val myDb = MyDb(applicationContext)
In general we should encapsulate access to a local store in another class such as a DAO/Repository/Service instead of having them directly in the Activity. this promotes loose coupling between views and data/network access. This also decouples the lifecycle of your DB connection, from the lifecycle of the currently running activity, giving you more control and opportunity for reuse.
Try using a bound Service to and have your DB connections there. Because it is a bound Service, it'll only be around if there is an Activity around that binds to it. Each Activity will bind to the same instance of the Service so it means you wont have duplicate connections. When no Activities are bind to it, it'll automatically be destroyed, destroying the connection along with it.
For a more modern, structured approach, using Jetpack components, you can look at https://github.com/googlesamples/android-sunflower
I'm currently writing an App, it gets JSON from a website, and then lists the contents in a listview. Now since the API itself only returns names like this: "twisted_castle" instead of "Twisted Castle", I created a new class to substitute the generic names to the right names, which I previously added to the strings.xml.
Now I can get Strings via String test = getString(R.string.key) in the MainActivity, but since I created a new class for the Substitute to happen, I somehow can't use getString somehow.
I already discovered that I'll need to get/use the context of MainActivity somehow, but really any solution I found didn't work, and also I'm a bit irritated on how the whole context thing works.
Anyone can help me with this and maybe has a good explanation on how contexts work?
You can use Context as:
mcontext.getString(R.string.something);
all you have to do is init context in the class some where like:
static Context mcontext;
public void setmContext(Context context){
this.mcontext=context;
}
and call setmContext(this) from your activity or where ever you have context attribute
So I've been working with IOS development for the past couple of months and have used Core Data and NSFetchedResultsController extensively.
Core Data + NSFetchedResultsController : Detects changes to the database automatically and updates table elements accordingly.
Now I've switched over to Android development and I've been looking for an equivalent of the above. I've looked at various different classes available and am a little confused.
The different types of classes:
Cursor: Provides access to the result of a database query.
CursorAdapter : Links the (list, recycler) view with the a cursor and displays the objects.
ContentProvider: Provides access to database objects. Required for use of LoaderManager.
LoaderManager: Implemented by an Activity or a Fragment to load data without blocking UI
Loader: Loader which generates cursor objects when content has changed.
I think it's also worth mentioning I am using greendao, and I am using its generated ContentProvider.
Flow of updating
This is where I got a little iffy. This is my assumption.
Content Provider maintains a cursor -- which is used by LoaderManager and possibly also CursorAdapter.
When a change occurs from the database, the Loader has a ForceLoadContentObserver which observes the cursor and calls onLoadFinished when its content is changed.
Normally a cursor adapter would call swap() inside the onLoadFinished(), resulting in a update of the table.
Keeping the above in mind, I created a ContentProvider and implemented LoaderManager but the function onLoadFinished() isn't being called when I persist a new object (using greenDao) -- which led me to start questioning whether I am understanding the process correctly. Here is a snippet of code to show what I have generally coded so far.
Fragment class
public class MissionPageFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
// Various initialization methods
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(0, savedInstanceState, this);
}
#Override
public Loader onCreateLoader(int id, Bundle args) {
ContentProvider.daoSession = Main.daoSession;
Uri uri = ContentProvider.CONTENT_URI;
// Other initializations
CursorLoader cursorLoader = new CursorLoader(getContext(), uri, projections, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
System.out.println("Should be called when a new item is persisted... but not called =(");
}
// Other methods
}
If someone could confirm whether I am thinking about the process correctly and/or shed light on what might be going wrong, I would appreciate it a lot.
Edit 1
Here is a snippet of the query() function in the ContentProvider subclass generated by greenDao.
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case MISSION_DIR:
queryBuilder.setTables(TABLENAME);
break;
case MISSION_ID:
queryBuilder.setTables(TABLENAME);
queryBuilder.appendWhere(PK + "="
+ uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = getDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection,
selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
Solution
I just wanted to share how I implemented all of the aforementioned classes with GreenDao. Let me know if there's a better way to do this, but I feel like this is good enough.
Generate a ContentProvider subclass by adding the following code snippet to the GreenDaoGenerator class
Entity entity = new Entity();
entity.addContentProvider();
Check if the ContentProvider subclass methods are called appropriately. Add the javadoc part to AndroidManifest.xml. For me, I also had to change the generated ContentProvider class BASE_PATH variable to another variable like the following.
public static final String BASE_PATH = "MYTABLENAME";
Add LoaderManager, Loader to the Activity/Fragment class like the one I wrote above. You will also have to set the daoSession object before the ContentProvider is used. I've moved the below snippet to another initializer class so that other Activity/Fragment classes may use it as well.
ContentProvider.daoSession = Main.daoSession;
I'm using a RecyclerView so I subclassed the CursorRecyclerViewAdapter class provided here https://gist.github.com/skyfishjy/443b7448f59be978bc59 with a little customization. You should be able to use a simple CursorAdapter if you are using a ListView. Since the Loader is listening for updates, the Adapter doesn't need to listen for updates.
Now the ContentProvider subclass is able to update the view due to this line
getContext().getContentResolver().notifyChange(uri, null);
which is automatically generated by GreenDao. What this means is that you can use ContentProvider for all CRUD operations and the view will automatically update accordingly. This seemed to defeat the purpose of using an ORM. As such, I now do normal GreenDao operations and call the notifyChange manually after each insertion, deletion, update.
GreenDaoObj obj = new GreenDaoObj();
obj.insert();
getContext.getContentResolver().notifyChange(MyContentProvider.CONTENT_URI, null);
I don't think there is a better way than this as I don't really want to touch the GreenDao generated code for Model and Dao objects. I suppose one could add custom CRUD functions which nests the generated CRUD methods, but that should be trivial.
I've been looking around and there wasn't a well documented way to use GreenDao with Loader/LoaderManager so I thought I would organize this here. Hopefully this helps anyone who is planning on implementing this.
There are just a couple of things you didn't get exactly right.
ContentProviders are Android components that provide access to data. That data can be stored in a relational database, flat file, a remote server, etc. Providers have a common REST-like interface and serve as an abstraction layer over the different options for data storage you have. ContentProviders can also be accessed from external applications (if configured properly) and this makes them the default way of sharing data between apps. Accessing them doesn't require a LoaderManager. They should be accessed via a ContentResolver.
LoaderManager is responsible for the Loader lifecycle and coordinating it with the Activity and Fragment lifecycles.
Loaders provide a lifecycle aware way to load data into activities or fragments. The CursorLoader is a particular implementation that comes with a tone of features - it uses a worker thread to keep the loading of the UI thread, it abstract using a ContentResolver to access a ContentProvider and also sets up a ContentObserver. The ContentObserver will listen for updates on the query URL and reload data if needed.
In order to get ContentObserver notifications to work, you have to make sure a couple of things are in place. First, your ContentProvider should propagate changes to the observers. This is done using getContext().getContentResolver().notifyChange(url, observer). Then, if you have a CursorLoader that executed a query on the notified URL, it will be automatically reloaded.
I am using Java / Play Framework 2.1.0.
I have found other questions asking how to access application.conf, and I tried two methods:
Play.application().configuration().getString("my.thing");
and
ConfigFactory.load().getString("my.thing");
In both cases I dont get anything back. I am trying to do this in onStart of my Global class. Maybe onStart happens before configuration is loaded?
How can I access values in application.conf from within onStart? (Or, to be more precise, how do I access values in myapp.conf which is included in application.conf)
Can you verify that your onStart is getting called at all?
The configuration values are loaded and accessible at that point. In fact, you are getting the play.Application instance passed as an argument, so you can just do this:
public void onStart(Application app)
{
super.onStart(app);
String value = app.configuration().getString("my.thing");
// do something with value
}