The documentation at http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getWritableDatabase%28%29 states:
Database upgrade may take a long time,
you should not call this method
[getWritableDatabase] from the
application main thread, including
from ContentProvider.onCreate().
This begs the question: for best practice, where should getWritableDatabase be called from?
My feeling is that, perhaps, it should be called once upon application launch with a callback to mark the database as ready. Is this correct?
For small and agile databases I imagine this isn't much of an issue.
Otherwise, I'd use an always-wonderful AsyncTask, called from onCreate.
It can be called from anywhere, but it should not be called from the UI thread because you don't know how long the process will take (especially with the different file systems in use). Even if you know the database should be small, you don't know about the file system (can it perform more than one job at a time? are there are thousand other jobs waiting in line already?). You can use an AsyncTask or a Thread to call getWriteableDatabase.
It seems that the intended use of the open helper framework, is to open the db on activity start, and close it when the Activity is destroyed.
In an AsyncTask from within onCreate()...
new StartupTask().execute();
The AsyncTask Thread.sleep() below is just to give enough time to show the dialog so that you can see it work. Obviously take that out when you're done playing. ;)
private class StartupTask extends AsyncTask
{
private ProgressDialog progressDialog;
#Override
protected Object doInBackground(final Object... objects)
{
openHelperRef.getWritableDatabase();
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return null;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
runOnUiThread(new Runnable()
{
public void run()
{
progressDialog = ProgressDialog.show(
MyActivity.this, "Title",
"Opening/Upgrading the database, please wait", true);
}
});
}
#Override
protected void onPostExecute(Object object)
{
super.onPostExecute(object);
progressDialog.dismiss();
}
}
in onDestroy()...
openHelper.close();
Related
I'm using AsyncTask to populate SQLite database. I'm downloading data from a certain webpage and putting it in SQLite tables. The thing is, I want to either download 100% of the data or none. So in case the AsyncTask is for some reason interrupted, I want to delete all the data that has been downloaded so far.
This is how I tried to do it:
#Override
protected void onCancelled() {
super.onCancelled();
dbHandler.deleteFromDatabase(razred);
Log.i("TAG", "AsyncTask cancelled");
}
I thought that "onCancelled" will execute if AsyncTask is interrupted in any way but it doesn't. What could I do to erase data that was made with AsyncTask in case it is cancelled in any way? (ex. activity paused, activity destroyed, internet connection interrupted etc.)
You're on the right track, but in your doInBackground() you also need to specifically call isCancelled() to check if it's cancelled and then return from doInBackground(). Then your code will work properly.
Refer to the AsyncTask documentation for "Cancelling a task"
Here's the quote from the documentation for easy reference:
A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
EDIT: Per request, some sample code:
private class MyAsyncTask extends AsyncTask<Void,Void,Void> {
private SQLiteDatabase db;
#Override
protected void onPreExecute() {
// any kind of initialization or setup needed before the
// background thread kicks off. remember: this is still on
// on the main (UI) thread
// since youre doing DB I/O, Ill make believe Im initializing the DB here
db = DatabaseHelper.getInstance(MainActvity.this).getWritableDatabase();
}
/*
* The background thread to do your disk and network I/O. If you need
* to pass in any parameters, this is the first Void in the template
*/
#Override
protected Void doInBackground(Void... params) {
// other stuff you need to do in the background. Since you want an
// all-or-nothing type thing, we will use a transaction to manually
// control the db
db.beginTransaction();
try {
// do network I/O to retrieve what you need and then write to DB.
...
... // if theres a loop in here somewhere when reading the data, check !isCancelled() as part of the condition or as one of the first statements and then break
...
db.setTransactionSuccessful(); // assuming everything works, need to set
// this successful here at the end of the try
} catch (InterruptedException ie) { // or some other exception
cancel(true); // heres where you can call cancel() if youve been interrupted
} catch (IOException ioe) { // if your network connection has problems
cancel(true);
} finally {
db.endTransaction();
// other cleanup, like closing the HTTP connection...
// no need to close the DB if you implement it properly
}
return null; // if there was some return value, that would go here
}
#Override
protected void onCancelled(Void result) {
// depending on how you implement doInBackground(), you may not even need this,
// unless you have a lot of other "state" you need to reset aside from the DB transaction
}
#Override
protected void onPostExecute(Void result) {
// any other items to do on main (UI) thread after doInBackground() finishes
// remember, this only gets called if cancel() is not called!
}
}
Hope that helps!
I know this is not exactly what you've asked for, but I have to say you are doing it all wrong by using the AsyncTask.
There are many cases where your async task will be terminated without you being able to do anything. For such critical tasks as this one, use a Service.
With a Service you can till the system to restart your service in case it is terminated prematurely. You then can continue what you started, or start all over again (deleting all previous downloads...etc).
With an AsyncTask, if the system decided to terminate your async task prematurely, you are not notified nor the AsyncTask is restarted. It just dies in complete silence.
I think in the onpostexecute you could handle anything you wanted to.
private class ParseDownload extends AsyncTask<Summary, Void, Boolean> {
#Override
protected Boolean doInBackground(Summary... urls) {
for (Summary url : urls) {
url.dosomething();
if (isCanceled();) { return false;}
}
return true;
}
#Override
protected void onPostExecute(Boolean result) {
if (!result) {
// delete * from yourtable here...
// and mark the download incomplete etc.
}
}
}
Good Luck
I'm trying to do an Android game using a Thread which repeats a loop for draw, move and others.
I have a problem with the execution of a method, which searches a value with a "do while" loop. When this method is executed, the thread does not continue until this process does not end.
What would be the best option for avoid this? Make another thread within that method? If you can give an example I'd really appreciate it.
Here's some pseudocode:
void mainLoop(){
drawElements();
moveElements();
//...
//...
reposition();
}
void reposition(){
// this stops my thread
do{
// do stuff
}while(!end);
// do stuff
}
As wqrahd suggested use AsyncTask.
I assume mainLoop is a main UI thread.
public class RepositionClass extends AsyncTask {
private Context mContext;
public RepositionClass(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
// do UI related here, this function will run in main thread context.
}
#Override
protected Boolean doInBackground(String... params) {
// call non-ui(computation intensive) part of reposition function here.
return true;
}
#Override
protected void onPostExecute(Boolean result) {
// do UI related part of reposition function here.
}
}
Creating another thread won't help you if you still have to block and wait for the loop to complete the search. The problem really is what is happening in the "do stuff" loop, you just need to optimize that to solve the issue.
use asyntask and in asyntask's doInBackground , do your thread work and in asyntask's onPostExecute call your repositionMethod.
I have this lines of code:
1) m_ProgressDialog = ProgressDialog.show(m_Context, "", m_Context.getString(R.string.dictionary_loading));
2) //important code stuff: interact with db, change some textview values (= 2-3 seconds if i'm unlucky)
3) m_ProgressDialog.dismiss();
But what happens is that phase 2) happens before 1).. which is wrong. First UI freezes then dialog appears..
phase 2) is some code that interacts with DB, might also change some textViews..but since this might take a while i decided to show that progress dialog so that user would know that really important stuff is going on. I cant use Async for these operations since UI code & db code is mengled, it will only complicate my life
How can i force dialog to show at request ??.. to me it seams that code presented just adds it in a "To do list when i have some free time & i dont have time now" stack..
You are doing your work on the ui thread. You should use a separate thread for this to keep the UI (progress bar) responsive. Have a look at AsynchTask.
Do not use UiThread for background operations it lead to freeze of screen.You have to use separate thread like Asyc Task.
do like below
in
onCreate()
{
dialog.show();
new DownloadFilesTask().excute()
}
class DownloadFilesTask extends AsyncTask<Void,Void,Void>
{
protected Long doInBackground(URL... urls) {
//Background operation
}
return null;
}
protected void onProgressUpdate(Integer... progress) {
}
protected void onPostExecute(Long result) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
//Update you Ui here
dialog.dismiss();
}
});
}
}
For most of cases if you want to simply have 2 methods, ShowLoading() and HideLoading() just use this
public static void ShowLoading()
{
HideLoading();
myLoadingThread = new Thread(new ThreadStart(LoadingThread));
myLoadingThread.Start();
}
private static void LoadingThread()
{
Looper.Prepare();
myProgressDialog = new ProgressDialog(myActivity,
Resource.Style.AppTheme_Dialog);
myProgressDialog.SetMessage("Loading..."); // Or a #string...
myProgressDialog.SetIcon(Resource.Drawable.your_loading_icon);
myProgressDialog.SetProgressStyle(ProgressDialogStyle.Spinner);
myProgressDialog.SetCancelable(false);
myProgressDialog.Show();
Looper.Loop();
}
public static void HideLoading()
{
if (myProgressDialog != null)
{
myProgressDialog.Dismiss();
myProgressDialog = null;
}
if (myLoadingThread != null)
myLoadingThread.Abort();
}
Now I declare and explain the followings variables I used on my code sample, one of them is global, yes, if you don't like to use global vars, or you want to have 2 loading dialogs at a time (wtf...) look for another solution. This is just the simplest way, most friendly and free of weird code with nested methods, new classes and inheritance everywhere for such a simple thing:
private Thread myLoadingThread;
private ProgressDialog myProgressDialog;
// Some people will hate me for this, but just remember
// to call myActivity = this; on each OnStart() of your app
// and end with all your headaches
public Activity myActivity;
As I've asken on another question HERE it seems that the PackageManager.getInstalledPackages() doesn't play nice with Threading. As CommonsWare stated HERE:
Perhaps the PackageManager needs to be invoked on the main application
thread, for some reason
So having it on a thread gets undesired behavior, entering and exiting a few times in my Activity makes the list of displayed apps sometimes with items, sometimes empty. Having everything in the UI Thread works like a dream, loads fine everytime. The thing is, the user expects some sort of feedback and I need to provide one. As I start the activity, the screen remains black for 3-4-5-6 seconds (depending on the device and apps installed). How can I provide some sort of feedback ? I am thinking of a ProgressDialog but I don't know how can I start it. Thank you.
As discovered, the loop to work through the applications takes awhile (which can be done in a separate thread), compared to the call to PackageManager.getInstalledPackages() (which has to be done on the UI thread).
Use Async to do background work and show indicator while loading data.
in you onCreate(). call new AsyncCommonDataFetcher(this).execute();
public class AsyncCommonDataFetcher extends AsyncTask<Void, Void, Void> {
Context mContext = null;
private ProgressDialog mProgressIndicator = null;
public AsyncCommonDataFetcher(Context ctx) {
mContext = ctx;
}
protected void onPreExecute() {
mProgressIndicator = ProgressDialog.show(((Activity) mContext), null,
"Please wait", true);
}
#Override
protected Void doInBackground(Void... voids) {
// Do what ever work you like to do. It will do this in backgound and show user a indicator to wait.
}
#Override
protected void onPostExecute(Void voidInstance) {
try {
if (mProgressIndicator != null) {
mProgressIndicator.hide();
mProgressIndicator.dismiss();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
Try the following for ProgressDialog in the onCreate() of your activity
this.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
ProgressDialog LoadingDialog = ProgressDialog.show(this, "", "Loading..", true);
And then dismiss it when the process causing the delay is over
LoadingDialog.dismiss();
I have listed of products with different category. I have to sort them. Because of the queries, It is taking more time to load. Between two activities, the screen is coming black. I want to run the query in the background. How can I do that and how to use its result in main activity?
private class InsertTask extends AsyncTask {
String cat;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(String... params) {
Boolean success = false;
try {
category(cat);
success = true;
} catch (Exception e) {
if(e.getMessage()!=null)
e.printStackTrace();
}
return success;
}
#Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
}
private void category(String category) {
try{
Cursor1 = mDbHelper.fetchcategory(category);
}catch(Exception e){
Log.v("Excep", ""+e);
}
}
And when called
InsertTask task = new InsertTask();
task.execute();
I have listed the category in buttons. How can I get the values then?
You should use AsyncTask for that. And some more info.
Its good you have thought of AsyncTask. Firstly, you can declare this class as inner in you class activity (if you haven't previously did) and so you are able to access you view class members.
You can do this also by creating thread and one handler that will be used to update your UI components. Remember that if you use threads you'll need to lock/unlock your database object because of the thread safety(if any other thread is accessing the database for any reason). Read more about thread safety of dbs.
I was doing some searching myself, and I came across this read, its rather long but looks extremely helpful, with lots of code examples. (I bookmarked it for myself).
Threads, Async, and Handlers O MY!
But some form of threading is the ticket.
From Android dev.
(My favorite code snippet)
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
//Do Work here
}
}).start();
}