a Service, a Thread, an Activity and a static ArrayList - java

I have a non-sticky service that's called on a regular basis via a broadcastreceiver to start a thread that'll perform some tasks. While the thread is running an ongoing notification shows some progress information, and a button to bring up a status page.
This status page shows a lists of items curerntly being processed, this list is a static ArrayList used by both the thread and this activity. When the status Activity is started I have a null check:
if(Global.statusItems == null)
{
Global.statusItems = new ArrayList<StatusPageItem>();
}
The thread is still running, and has perfectly fine access to the ArrayList, but as soon as the Status Activity is brought up it'll recreate the ArrayList as if it were null.
So far I haven't been able solve the issue without saving the list using an ObjectOutputStream and reloading when the status page is started. Is there a more elegant solution I could use?
Regards,
Quint.

Is it possible that your service is running on a different process?

You need to make sure that the 2 lines of code (null test and creation of a new list) are atomic and that the allocation is visible from other threads.
The easiest way to do that is to synchronize that piece of code:
synchronized(Global.class) {
if(Global.statusItems == null) {
Global.statusItems = new ArrayList<StatusPageItem>();
}
}
However, if you need to read the list from one thread and write to it from another thread, you will need to add extra synchronization when adding/removing/iterating to make sure that both treads see the same list - if you don't, it is possible that the writing thread adds an item to the list but the reading thread does not see it.
The easiest way would be to use a thread safe implementation of list:
synchronized(Global.class) {
if(Global.statusItems == null) {
Global.statusItems = new CopyOnWriteArrayList<StatusPageItem>();
}
}
If memory / object creation is a concern (CopyOnWriteArrayList is not very efficient from that perspective), you can also use a synchronized collection instead:
synchronized(Global.class) {
if(Global.statusItems == null) {
Global.statusItems = Collections.synchronizedList(new ArrayList<StatusPageItem>());
}
}
In that case, make sure you lock on the collection when iterating:
synchronized(Global.statusItems) {
for (StatusPageItem item : Global.statusItems) {
}
}

Related

JavaFX task/thread not filling tableview consistently

So, i need to fill a Table View using a JavaFX thread but the table is being filled only ~70% of time. I am looking at my code and i really can't find where the problem comes from, my guess is that the task is somehow being executed before the data is successfully retrieved/processed from db. Thanks is advance :)
private Executor exec;
private ObservableList<User> cellData = FXCollections.observableArrayList();
.
.
.
public void fillTable(HashMap<String,Object> whereClause){
Task<List<User>> task = new Task<List<User>>(){
#Override
public ObservableList<User> call(){
cellData.clear();
cellData.addAll(userRepository.getAll(whereClause));
userId.setCellValueFactory(new PropertyValueFactory<>("userID"));
userName.setCellValueFactory(new PropertyValueFactory<>("userName"));
userMail.setCellValueFactory(new PropertyValueFactory<>("userMail"));
userPhone.setCellValueFactory(new PropertyValueFactory<>("userPhone"));
isAdmin.setCellValueFactory(cellData -> {
String isAdminAsString = cellData.getValue().isAdmin() ? "Admin" : "Medic";
return new ReadOnlyStringWrapper(isAdminAsString);
});
isDeleted.setCellValueFactory(cellData -> {
String isActiveUser = cellData.getValue().isDeleted() ? "No" : "Yes";
return new ReadOnlyStringWrapper(isActiveUser);
});
logger.info("Cell values set");
return cellData;
}
};
exec.execute(task);
task.setOnFailed(e -> System.out.println(task.getException().getMessage()));
task.setOnSucceeded(e -> userTable.setItems((ObservableList<User>) task.getValue()));
logger.info("Fill user Table Task executed");
You don't give enough context for a proper, fully confident answer, but my guess is you're encountering issues relating to threads. JavaFX is not thread-safe; using the wrong thread to update the UI can lead to undefined behavior, such as the data only appearing ~70% of the time. There's an important rule in JavaFX that you must always follow:
Never read or write the state of objects that are connected—directly or indirectly—to a live scene graph on a thread other than the JavaFX Application Thread.
Your code does not follow this rule. Inside the call method of your Task you are structurally modifying cellData and setting the cellValueFactory of various TableColumns. This leads to said objects being modified by whatever thread is executing the Task. If the Executor is any hint, that thread is definitely not the JavaFX Application Thread.
I'm not sure why you're setting the cellValueFactory of your TableColumns inside the call method in the first place. The cell value factory is configuration that only needs to be done once—when you create the TableColumn (or shortly thereafter). In other words, configuring the cell value factory in the call method is wrong not just because it happens on a background thread but also because it happens each time you execute the Task. Remove the set-the-cell-value-factory code from the call method and move it, if needed, to where you're creating the TableColumns. If you're using FXML, and the TableColumns are created for you and injected, then the controller's initialize method is a good place for this sort of configuration.
Your cellData list is connected to your TableView, if not at first then definitely after the first successful execution of your Task. Modifying cellData on a background thread will notify the TableView of those changes on the same thread (listeners are invoked on the same thread that made the change). The easy solution is to have your Task return a new List and then update the TableView if successful.
Task<List<User>> task = new Task<List<User>>() {
#Override protected List<User> call() throws Exception {
return userRepository.getAll(whereClause);
}
});
task.setOnSucceeded(event -> userTable.getItems().setAll(task.getValue()));
task.setOnFailed(event -> task.getException().printStackTrace());
exec.execute(task);
The setAll method of ObservableList will first clear the list then add all the elements of the given collection (or array). This is somewhat more efficient than calling clear followed by addAll because it results in only one change event. Also, if you want to continue using cellData you can, assuming you've previously set it as your table's items; just use cellData.setAll(task.getValue()) instead.
Regarding the use of:
task.setOnSucceeded(e -> userTable.setItems((ObservableList<User>) task.getValue()));
Since you clearly expect an ObservableList<User> to be returned, you should be using a Task<ObservableList<User>> instead of a Task<List<User>>. This will mean getValue() returns ObservableList<User> and thus the cast becomes unneeded. However, if you follow the advice above, then this is irrelevant.

Use rx java to load reference data but blocking if necessary

I am trying to implement a solution for storing reference data in the database of my app.
The data is initially stored as JSON files, which I will need to sync from a server on each launch. I have a local copy of the files baked into the app. Each launch I have to check shared preferences for a version. And if it not present, I assume it is the first launch. So i need to read in the files, write the files to the database and fire on completed when that is done. The first screen expects this data to be in the database, so I will be not showing the UI for that screen in this scenario, until the process completes.
However in the future the network call to sync these files can happen asynchronously so want to be able to fire on completed on my observable as soon as i see the shared prefs have a version number and then ill kick of the update completely asynchronously
How can i set up a stream to represent this. I think the stream type will probably be void and i will just fire onCompleted/error as the subscriber doesnt care about the data, only what the process is complete
You could do something like this:
updateChecker.hasUpdates()
.flatMap(hasUpdates -> {
if (hasUpdates) {
return dataUpdater.update();
}
return Observable.just(false);
})
Assuming that
class UpdateChecker {
public Observable<Boolean> hasUpdates() {
return Observable.just(true); // Replace by API call
}
}
class DataUpdater {
public Observable<Boolean> update() {
// update the database here
return Observable.just(true);
}
}

GreenDao how to implement callbacks

I have a trouble, i need to get event/callback when i try to write to database.
I added greenDao lib to project, and i able to write/delete in db.
But no idea how to get callback after some operation under db.
In introduction to lib i read "AsyncOperationListener for asynchronous callback when operations complete".
Used this tutorial:
http://blog.surecase.eu/using-greendao-with-android-studio-ide/
Can anybody help me with this trouble?
UPD:
ok here we added some list in storage
getMyObjectDao().getSession().startAsyncSession().insertOrReplaceInTx(MyObject.class, list);
error here
List<MyObject> items = getBoxDao(c).getSession().startAsyncSession().loadAll(MyObject.class);
How can we asynchronously load data from db?
Is this correct solution?
#Override
public void onAsyncOperationCompleted(AsyncOperation operation) {
String operationIs = null;
switch (operation.getType()) {
case LoadAll:
itemsList = BoxRepository.getAllBoxes(getApplicationContext());
By default all the operations are performed synchronously, eliminating the need to get any callback. But the recent version of GreenDAO introduces AsyncSession, which can be used to perform operations asynchronously and also provides a way set listener on it. See the example below:
AsyncSession asyncSession = App.getInstance().daoSession.startAsyncSession();
asyncSession.setListener( new AsyncOperationListener() {
#Override
public void onAsyncOperationCompleted(AsyncOperation operation) {
// do whats needed
}
});
asyncSession.insert(MyObject);
Simple ask if anything unclear!

Serialize ArrayList on device

I have developed an application in Android that downloads a lot of data through XML query REST.
The problem is that every time you start the app takes a long time to download the data.
My question is:
How can I serialize these data, and update perhaps after a certain period of time?
I want some advice or idea to implement, or even better an example.
thanks
Use that one to serialize:
http://simple.sourceforge.net/
You can schedule an async task or a thread to update it.
Example for a thread that serializes data incl. a lock (only parts of the code)
static final Object sDataLock = new Object();
Serializer mSerializer;
class AsyncSave implements Runnable
{
Object mSerialize;
File mStorage;
public AsyncSave(Object serialize, File storage)
{
mSerialize = serialize;
mStorage = storage;
}
#Override
public void run()
{
try {
synchronized (sDataLock) {
// write
mSerializer.write(mSerialize, mStorage);
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
}
How can I serialize these data, and update perhaps after a certain period of time?
You can use thread/async task if you want certain data to be downloaded in certain activity. The async task/thread will be destroyed if the activity is destroyed.
If you want to download the data in certain time, use a Service instead. With a service, your data will be downloaded even if the apps is closed. For example, you can set your apps to download certain data once a day.

Wait for completion of last statement before moving to next

I have been working on a library for Android. The library has a method which fetches data from a web service and puts it in a database. The fetching part is, of course, not done on the main thread. Here's a sample method:
public void fetchData() {
remoteTable.get(new TableOperationCallback<TEntity>() {
public void onCompleted(TEntity entity, Exception exception, ServiceFilterResponse response) {
if (exception == null) {
//CALBACK RECEIVED
//Put data in local database.
}
});
}
Now, somewhere else in my app, where the library is being consumed, I do something like this to refresh the data:
public void refreshData(){
mylibrary.fetchData();
List<MyItems> mList = localtable.getItems();
}
Here, the first statement will go and fetch the data on background thread. So, the second statement will be executed even before the data is actually fetched. How do I get around this? I want the second statement to be executed only after the callback of the first is complete.
Edit: If it matters, the method refreshData is not in any activity. I put that method in a separate class (and called it ViewModel - .NET habit!).
You can have a look at this link
Android Update Current Activity From Background Thread
You basically want a Callback interface. When the task in the library completes, then you do what you have to do

Categories