Android Room + AsyncTask - android-asynctask

My team have developed a new Android app which makes extensive use of Room.
I am unsure whether we are using AsyncTask correctly.
We have had to wrap all calls to insert/update/delete in AsyncTasks which results in a huge number of AsyncTasks. All the calls into Room are from background services. There is no direct Room access from activities or fragments - they get everything via LiveData.
An example call to insert a row:
AsyncTask.execute(() -> myModelDAO.insertInstance(myModel));
With this in the DAO:
#Insert
void insertInstance(MyModel model);

To complete #CommonsWare answer, you can use the Executor class to execute Room queries into a background thread.
Executor myExecutor = Executors.newSingleThreadExecutor();
myExecutor.execute(() -> {
myModelDAO.insertInstance(myModel)
});
Google showed an example on their Android Architecture Components guide.

All the calls into Room are from background services
Then you should not be using AsyncTask. AsyncTask is only for when you want to do work on the main application thread after doing background work, and that is almost never the case with a service. Use something else (thread, thread pool, RxJava, etc.). This has nothing specific to do with Room.

AsyncTask.execute(() -> myModelDAO.insertInstance(myModel));
Looking like incorrect you can use Simple Thread/Threadpool/Schedulers etc

You can use a callback like Consumer<List<object>>callback.
For example:
roomManger.getAllUsertById(user.getId(), this, new Consumer<List<User>>() {
#Override
public void accept(List<Product> listOfUser) {
users.addAll(listOfUser)}

Related

How to execute long running/polling operations in Eclipse Vert.x

I have a scenario where we need to keep on polling a database table for all active users and perform an api call to fetch any unread emails from their inbox. My approach is to use two verticles, one for polling and another for fetching emails for an user. The first verticle when found an user, sends a message(userId) to the second verticle through an event bus to fetch emails. That way, I can increase the number of second verticle instances required when there are lots of users.
Following two ways I found I can use to poll the database for active users and then perform an api call for each user.
vertx.setPeriodic
vertx.executeBlocking
But in the manual, its mentioned that for long running/polling tasks, its better to create an application managed thread to handle the task.
Is my approach for the problem correct, or is there a better approach to solve the problem at hand?
If I go through an application managed thread, can you please help illustrate with an example.
Thanks.
You can create a dedicated worker thread pool for that, and run your periodic tasks on it:
public class PeriodicWorkerExample {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new MyPeriodicWorker(), new DeploymentOptions()
.setWorker(true)
.setWorkerPoolSize(1)
.setWorkerPoolName("periodic"));
}
}
class MyPeriodicWorker extends AbstractVerticle {
#Override
public void start() {
vertx.setPeriodic(1000, (r) -> {
System.out.println(Thread.currentThread().getName());
});
}
}

SQLite-net and SQLite-WinRT at the same time in Windows runtime apps

Previously I had used SQLITE-NET library for my all sqlite database tasks and it works well.
But my app has huge number of data to insert and it took a lot of time. So I decided to use SQLITE-WinRT wrapper only where bulk insert is needed as SQLITE-WinRT wrapper seems to provide feature like preparing statements then binding data and then execute them which gives faster processing and increases performance.
In my app, there are lots of CRUD operations that uses SQLITE-NET methods and I left as it is since it is hard to completely switch from SQLITE-NET library to SQLITE-WinRT wrapper.
My app has background task that runs and processes some web-service calls and lot of CRUD operations using only SQLITE-NET library.
Whenever I tried to bulk insert using SQLITE-WinRT wrapper using prepared statements, in case background task is running, it always throws Busy exception in SQLITE-NET library. I know its reason, background service does lot of CRUD operations using SLITE-NET library. So while bulk inserting using SQLITE-WinRT wrapper it throws Busy exception as the sqlite database is already doing lot of tasks in background using SQLITE-NET.
So, my question is how to handle this situation. Please suggest me some ideas to handle such cases. I thought of two ideas:
Stopping background service while bulk inserting (In background,
there is series of long tasks like calling web-service and doing work
with SQLite db, stopping background service at once might not be
good idea )
Closing all SQLITE-NET connection (didn't work as expected though)
Any help would be appreciated. Thanks in advance.
While bulk inserting, I started like this:
string dbPath = "collection.sqlite";
var file = await ApplicationData.Current.LocalFolder.GetFileAsync(dbPath);
var db = new SQLiteWinRT.Database(file);
await db.OpenAsync(SqliteOpenMode.OpenReadWrite);
using (var statement = await db.PrepareStatementAsync("INSERT INTO Forms(ServerFormId,FormFileName,FormStatusId,PriorityId) VALUES(?,?,?,?)"))
{
await db.ExecuteStatementAsync("BEGIN TRANSACTION");
statement.Reset();
statement.BindTextParameterAt(1, "0");
statement.BindTextParameterAt(2, formName);
statement.BindTextParameterAt(3, formStatusId);
statement.BindTextParameterAt(4, priorityId);
await statement.StepAsync().AsTask().ConfigureAwait(false);
}
await db.ExecuteStatementAsync("COMMIT TRANSACTION");
SQLite-WinRT: https://blogs.msdn.microsoft.com/andy_wigley/2013/11/21/how-to-massively-improve-sqlite-performance-using-sqlwinrt/
SQLite-net: http://www.codeproject.com/Articles/826602/Using-SQLite-as-local-database-with-Universal-Apps
I'm afraid that the only option is using lock or semaphore before accessing the database.
The lock mechanism guarantees that only one thread does inner code block. Other threads synchronously waits.
readonly object sync = new object();
void MyMethod() {
lock (sync) {
...
}
}
Semaphore is similar, but the inner code block can be executed maximally by n threads.
Please see more info about SemaphoreSlim on MSDN.

using timer in background worker in windows phone

I am develping an app which load some url, parse them, keep them into sqlite db and the UI will read the saved data and show them in controls. This progress should be done in almost an infinit loop. For having fast response i plan to read the data from db in main thread and have an other thread (background worker) to load the data and insert it into db. Is it logical and possible to run read and write process in dispatchertimer, one timer in main thread and the other inside the background worker? and how? Or does anyone have better idea?
main thread:
DispatcherTimer _Timer1 = new DispatcherTimer();
_Timer1.Interval = _Interval;
_Timer1.Tick += _Timer1_Tick;
void _Timer1_Tick(object sender, EventArgs e)
{
// read data from db and show in controls
}
secondary thread:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
DispatcherTimer _Timer2 = new DispatcherTimer();
_Timer2.Interval = _Interval;
_Timer2.Tick += _Timer2_Tick;
}
void _Timer2_Tick(object sender, EventArgs e)
{
// write data into db
}
}
What you're planning to do wont work.
Both your _Timer1_Tick and _Timer2_Tick will run in the UI thread. If you perform some long-running operations there, it'll hang the UI.
I don't get it, why do you need timers at all? Using timers for anything else but measuring time intervals is rarely a good strategy. You could e.g. run your update process in the infinite loop in background, as soon as it put new data in the DB you call Dispatcher.BeginInvoke (passing any data you want) to notify your UI thread it should update itself with the newly available data.
And by the way, for the tasks like "send HTTP request, wait response, parse, store, repeat", the new async/await feature is a natural choice. For WP7 the functionality is available as "Async CTP" redistributable package for Visual Studio 2010, for WP8 it's already integrated into the framework. There're some compatibility issues between the 2, though.
load some url, parse them, keep them into sqlite db and the UI will read the saved data and show them in controls
Please don't do that. Don't create your own thread management system, just don't. I'm not saying it won't work, but it'll most likely backfire in the most horrendous and inexplicable ways. Like for example using a DisptacherTImer completely exploding in your face since it runs on the UI thread. If you really want to use threading considering ThreadPool.QueueUserWorkItem() or Task.Run() to start fire-and-forget actions.
Your workflow is also just strange, I don't get why you need to write data you already have to a DB, then read it back and only then use it. Won't it make more sense to use the deserialized data to sequentially write it to the DB and present it to the UI? Instead of doing the needless loop of involving Disk I/O considering you already have the data?
Have you considered using Messaging in your app? It's a pretty well known MVVM pattern implemented both in MVVM Light as the Messenger class and in PRISM as the EventAggregator. It seems to me that your system has a Message for "new data available from service" and that message has two subscribers: writing to a DB and updating the UI.

Eclipse RCP: Display.getDefault().asyncExec still blocking my GUI

I have a simple viewPart offering some text fields to enter parameters for a selenium test. After filling out these fields the user may start the test which approx. needs 30-45 minutes to run. I want my GUI to be alive during this test giving users the chance to do other things. I need a progress monitor.
I tried to put the selenium test in a job containing Display.getDefault().asyncExec to run it. But my GUI freezes after some seconds giving the busyindicator. The selenium does not update any other view but the progress monitor.
Is there another way to ensure that the job wont block my GUI?
Best,
Mirco
Everything executed in (a)syncExec is using the display thread and therefore blocking your UI until it returns. I suggest you use Eclipse Jobs. This will use the progress indicator that the workbench already offers out of the box.
I would suggest to split your code into code that updates the UI and the code that executes other business. Execute all of it in a separate thread, and when you need to retrieve or set some action to the UI then use the "Display.getDefault().asyncExec".
Thread thread = new Thread("Testing") {
// some shared members
public void run() {
someBusiness();
// or use syncExec if you need your thread
// to wait for the action to finish
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
// UI stuff here
// data retrieval
// values setting
// actions trigging
// but no business
}
});
someBusiness();
};
thread.start();

Windows Forms Threading and Events - ListBox updates promptly but progressbar experiences huge delay

Our team is creating a new recruitment workflow system to replace an old one. I have been tasked with migrating the old data into the new schema. I have decided to do this by creating a small Windows Forms project as the schema are radically different and straight TSQL scripts are not an adequate solution.
The main sealed class 'ImportController' that does the work declares the following delegate event:
public delegate void ImportProgressEventHandler(object sender, ImportProgressEventArgs e);
public static event ImportProgressEventHandler importProgressEvent;
The main window starts a static method in that class using a new thread:
Thread dataProcessingThread = new Thread(new ParameterizedThreadStart(ImportController.ImportData));
dataProcessingThread.Name = "Data Importer: Data Processing Thread";
dataProcessingThread.Start(settings);
the ImportProgressEvent args carries a string message, a max int value for the progress bar and an current progress int value. The Windows form subcribes to the event:
ImportController.importProgressEvent += new ImportController.ImportProgressEventHandler(ImportController_importProgressEvent);
And responds to the event in this manner using it's own delegate:
private delegate void TaskCompletedUIDelegate(string completedTask, int currentProgress, int progressMax);
private void ImportController_importProgressEvent(object sender, ImportProgressEventArgs e)
{
this.Invoke(new TaskCompletedUIDelegate(this.DisplayCompletedTask), e.CompletedTask, e.CurrentProgress, e.ProgressMax);
}
Finally the progress bar and listbox are updated:
private void DisplayCompletedTask(string completedTask, int currentProgress, int progressMax)
{
string[] items = completedTask.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (string item in items)
{
this.lstTasks.Items.Add(item);
}
if (currentProgress >= 0 && progressMax > 0 && currentProgress <= progressMax)
{
this.ImportProgressBar.Maximum = progressMax;
this.ImportProgressBar.Value = currentProgress;
}
}
The thing is the ListBox seems to update very quickly, but the progress bar never moves until the batch is almost complete anyway ??? what gives ?
Maybe you can try the BackgroundWorker component. It makes threading easier. Examples here:
BackgroundWorker Threads and Supporting Cancel
Using the BackgroundWorker Component in .NET 2 applications
BackgroundWorker Sample
Maybe outside of the scope but, to sometimes its useful to do an Application.DoEvents(); to make the gui parts react to user input, such as pressing the cancel-button on a status bar dialog.
Do you by any chance run Windows Vista? I've noticed the exactly same thing in some work related applications. Somehow, there seem to be a delay when the progress bar "animates".
#John
Thanks for the links.
#Will
There's no gain from threadpooling as I know it will only ever spawn one thread. The use of a thread is purely to have a responsive UI while SQL Server is being pounded with reads and writes. It's certainly not a short lived thread.
Regarding sledge-hammers you're right. But, as it turns out my problem was between screen and chair after all. I seem to have an unusal batch of data that has many many many more foreign key records than the other batches and just happens to get selected early in the process meaning the currentProgress doesn't get ++'d for a good 10 seconds.
#All
Thanks for all your input, it got me thinking, which got me looking elsewhere in the code, which led to my ahaa moment of humility where I prove yet again the error is usually human :)
Are you sure that the UI thread is running freely during all this process? i.e. it's not sitting blocked-up on a Join or some other wait? That's what it looks like to me.
The suggestion of using BackgroundWorker is a good one - definitely superior to trying to sledge-hammer your way out of the problem with a load of Refresh/Update calls.
And BackgroundWorker will use a pool thread, which is a friendlier way to behave than creating your own short-lived thread.
There's no gain from threadpooling as
I know it will only ever spawn one
thread. The use of a thread is purely
to have a responsive UI while SQL
Server is being pounded with reads and
writes. It's certainly not a short
lived thread.
OK, I appreciate that, and glad you found your bug, but have you looked at BackgroundWorker? It does pretty much exactly what you're doing, but in a standardised fashion (i.e. without your own delegates) and without the need to create a new thread - both of which are (perhaps small, but maybe still useful) advantages.

Resources