Room and RxJava Providing Inconsistent Results - rx-java2

This is my first time working with Room and RxJava. I'm getting some very inconsistent results when I'm reading from the DB. I have a nested RecyclerView, where the first simply shows the days of the week and the second shows the forecast for each day.
Sometimes when I launch the app, everything shows up right away. Other times, only the days will be shown, but not the forecast for each day. Other times, neither RecyclerViews are shown. However, if I view the DB using Stetho, the data is there within the device.
Here's how I've setup my Dao:
#Dao
public interface MyDao {
// Other CRUD methods
#Query("SELECT DISTINCT date FROM my_table")
Single<List<LocalDate>> getUniqueDays();
#Query("SELECT * FROM my_table WHERE date == :localDate")
Single<List<Forecasts>> getForecastForDay(LocalDate localDate);
}
I populate the first RecyclerView using the following:
Single<List<LocalDate>> source = MyApp.getDatabase().getDao().getUniqueDays();
source.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<List<LocalDate>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(List<LocalDate> localDates) {
mAdapter.refreshData(localDates);
}
#Override
public void onError(Throwable e) {
}
});
This is called within a fragment that displays the days of the week.
Then, within the adapter for the days of the week, I also need to populate the inner RecyclerView, which is done within my bind() of the ViewHolder:
public void bind(LocalDate date, int position){
// A bunch of other views being set
mHourlyForecasts.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false);
mHourlyForecasts.setLayoutManager(layoutManager);
mAdapter = new HourlyForecastAdapter(mContext);
mHourlyForecasts.setAdapter(mAdapter);
Single<List<Forecasts>> source = MyApp.getDatabase().getDao().getForecastForDay(date);
source.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<List<Forecasts>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(List<Forecasts> conditions) {
Timber.i("Size of conditions in onSuccess(): %d", conditions.size());
mAdapter.refreshData(conditions);
}
#Override
public void onError(Throwable e) {
}
});
}
However, I have no idea as to why the data isn't being shown consistently. Sometimes at startup the data isn't shown, sometimes it is. Sometimes I'll close out the app and re-open it and some data is missing. Or all of it is there. And again, the data is there in the DB when I inspect the device in Stetho, it's just not being shown within the RecyclerView(s).
If anyone can provide some guidance on this, it would be immensely appreciated...

Related

Android Mobile Apps query from the azure database returns last row only

There's more than 15 items in my azure database table called Events.
I've tried to run most of the commands found on
https://learn.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-android-how-to-use-client-library such as :
List<Events> results = eventsTable.execute().get()
and
List<Events> results = eventsTable.select("Events").execute().get();
and
List<Events> results = eventsTable.top(20).execute().get();
to return all the row items in the table. The queries seem to run on the last row of the table only and returns the last row or nothing at all when query is executed.
Though the ToDoItem Quickstart from Azure works perfectly with all the queries - which is odd.
Here's some of the code
ArrayList<Events> events = new ArrayLists<Events>();
private void EventsFromTable() {
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>(){
#Override
protected Void doInBackground(Void... params) {
try {
final List<Events> results = EventsTable.execute().get();
runOnUiThread(new Runnable() {
#Override
public void run() {
for (Events event : results) {
Events ev = new Events(event.getName(), event.getVenue(), event.getDate());
events.add(ev);
System.out.println("size is " +events.size());
<======This returns "size is 1"======>
}
}
});
} catch (final Exception e){
createAndShowDialogFromTask(e, "Error");
}
return null;
}
};
runAsyncTask(task);
}
Might any one know what the matter is?
Thanks
According to your code, the variable events seems to be a public shared instance of ArraryList in your Android app, so I don't know whether exists the case which multiple threads access it concurrently. The implementation of ArrayList class is not synchronized, please see here.
So please use the code below instead of the code ArrayList<Events> events = new ArrayLists<Events>(); when you shared the variable between UI thread and data async task thread.
List<Events> events = Collections.synchronizedList(new ArrayLists<Events>());
And I think it's better for copying data retrieved from table via addAll method, not add method for each, as the code below.
#Override
public void run() {
events.addAll(results);
}

Progress Indicator In a Table Cell

I have a table column which i added through Scene Builder, and with java code i made it editable like so
colSellingPrice.setCellFactory(TextFieldTableCell.<Sale, Float>forTableColumn(new FloatStringConverter()));
The problem is during updating the value in this tablecell, alot of calculations and many insertion and fetching is made which takes time to complete. Though i decided to put the update logic in a Task, i would also like to display a progress indicator in the tablecell UI while the logic is happenning.
This is what i have so far
colSellingPrice.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Sale, Float>>() {
#Override
public void handle(TableColumn.CellEditEvent<Sale, Float> t) {
Task task = new Task<Void>(){
private SaleTransaction st;
#Override
protected Void call() throws Exception {
Sale s = t.getRowValue();
// Logic, logic , logic
return null;
}
#Override
protected void succeeded() {
System.out.println("Price Updated.");
}
};
executor.submit(task);
}
});

RecyclerView.Adapter notifyDataSetChanged not working with AsyncTask Callback

I am sure it's just a simple fault, but I'm not able to solve it.
My RecyclerView.Adapter loads its data with help of an AsyncTask (LoadAllPersonsFromDb) out of a SQLite DB. The response is handled by a callback interface (ILoadPersonFromDb.onFindAll).
Here is the code of the Adapter:
public class ListViewAdapter extends RecyclerView.Adapter<ListViewViewholder> implements LoadAllPersonsFromDb.ILoadPersonFromDb {
private int layout;
private List<Person> persons;
private Context context;
private AdapterDataSetListener adapterDataSetListener;
public ListViewAdapter(int layout, Context context,
AdapterDataSetListener adapterDataSetListener) {
this.layout = layout;
persons = new ArrayList<>();
this.context = context;
this.adapterDataSetListener = adapterDataSetListener;
new LoadAllPersonsFromDb(context, this).execute();
}
#Override
public ListViewViewholder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
return new ListViewViewholder(view, context);
}
#Override
public void onBindViewHolder(ListViewViewholder holder, int position) {
holder.assignData(persons.get(position));
}
#Override
public int getItemCount() {
return persons.size();
}
#Override
public void onFindAll(List<Person> persons) {
Log.d("LISTVIEW", "Counted: " + persons.size() + " elements in db");
if (this.persons != null) {
this.persons.clear();
this.persons.addAll(persons);
} else {
this.persons = persons;
}
adapterDataSetListener.onChangeDataSet();
//notifyDataSetChanged();
}
public interface AdapterDataSetListener {
void onChangeDataSet();
}
}
As you can see, I tried more than one way to get it running. The simple notifyDataSetChanged did not do anything, so I made another interface which is used to delegate the ui information to the relating fragment. Following code documents this interface which is implemented in the relating fragment:
#Override
public void onChangeDataSet() {
Log.d("Callback", "called");
listViewAdapter.notifyDataSetChanged();
/*
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
listViewAdapter.notifyDataSetChanged();
}
});
*/
}
Here I also tried to put it on the MainUiThread but nothing works. I'm just not able to see where my problem is. Hopefully any of you guys can give me a hint.
The logging works, which is the prove for the working callbacks.
Thank you in advance.
PS: If you need any more code, just tell me and I will provide it.
instead of using the interface-llistener pattern, try this
#Override
public void onFindAll(List<Person> persons) {
Log.d("LISTVIEW", "Counted: " + persons.size() + " elements in db");
if (this.persons != null) {
this.persons.clear();
this.persons.addAll(persons);
} else {
this.persons = persons;
}
refereshAdapter(persons);
}
public void refereshAdapter(List<Person> persons){
listViewAdapter.clear();
listViewAdapter.addAll(persons);
listViewAdapter.notifyDataSetChanged();
}
To tell the background, I used RecyclerView in Version 23.1.1 because the latest 23.2.0 had some weird behaviour in holding a huge space for each card.
//Update: the problem with the space between cards, was because of a failure of myself in the layout file (match_parent instead of wrap_content). -_-
The upshot was using the latest version again and everything worked just fine. I have no idea why, but at the moment I am just happy, that I can go on. This little problem wasted enough time.
Maybe somebody has a similar situation and can use this insight.
Thx anyway #yUdoDis.

Dynamic DataGrid in GWT

I am trying to construct a DataGrid in GWT that will show an arbitrary dataset taken from an rpc method.
I have done some progress as I get the fields from a method and the data from another.
I have managed to construct the Datagrid and add the columns from the rpc.getFields() method and fill the table using an AsyncDataProvider.
The problem is that when I refresh the browser, it duplicates all the columns at the Datagrid. I cannot figure out what to do. I tried to remove first all the columns but no luck.
I attach the code if anyone have an idea.
public class MyCallBack implements AsyncCallback<List<Field>> {
DataGrid<Record> dg;
public MyCallBack(DataGrid<Record> dgrid) {
this.dg=dgrid;
}
public void onFailure(Throwable caught) {
Window.alert(caught.getMessage());
}
public void onSuccess(List<Field> result) {
for (int i=0;i<=result.size();i++) {
IndexedColumn ic = new IndexedColumn(i);
dg.addColumn(ic, result.get(i).getLabel());
}
}
public AsyncCallback<List<Field>> getCb() {
return this;
}
public void onModuleLoad() {
final DataGrid<Record> dg = new DataGrid<Record>();
MyCallBack mcb = new MyCallBack(dg);
DataProvider dp = new DataProvider();
DBConnectionAsync rpcService = (DBConnectionAsync) GWT.create(DBConnection.class);
ServiceDefTarget target = (ServiceDefTarget) rpcService;
String moduleRelativeURL = GWT.getModuleBaseURL() + "MySQLConnection";
target.setServiceEntryPoint(moduleRelativeURL);
rpcService.getFields(mcb.getCb());
dp.addDataDisplay(dg);
dg.setVisibleRange(0, 200);
SplitLayoutPanel slp = new SplitLayoutPanel();
slp.setHeight("700px");
slp.setWidth("1500px");
slp.addWest(dg, 770);
RootPanel.get().add(slp);
}
When you refresh a browser, all UI is lost. There is no difference between (a) show the UI for the first time or (b) show the UI after browser refresh.
Your comment "Only if I restart tomcat it works" suggests that the problem is on the server side. Most likely, you return twice the number of data points on a second call.
Try clearing the table before filling it like this:
public void onSuccess(List<Field> result) {
clearTable();
for (int i=0;i<=result.size();i++) {
IndexedColumn ic = new IndexedColumn(i);
dg.addColumn(ic, result.get(i).getLabel());
}
}
private void clearTable(){
while (dg.getColumnCount() > 0) {
db.removeColumn(0);
}
}

How can I correctly update a progress bar for an operation of unknown duration within an Eclipse wizard?

I have implemented a wizard for my Eclipse plug-in, showing several pages. One of these pages needs some lengthy initialization, that means it consists of a SWT table, which needs to be populated by information coming from an external source. This source needs to be activated first (one single method call that returns after a couple of seconds - I can not know in advance how long it will take exactly), before it can be used as input for for the table viewer. This initialization is currently done by the table model provider when it needs to access the external source for the first time.
Therefore, when I enter the wizard page, I would like to show a dummy progress bar that just counts up for a while. My approach was the following, but unfortunately does not work at all:
private void initViewer() {
IRunnableWithProgress runnable = new IRunnableWithProgress() { // needed to embed long running operation into the wizard page
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
SubMonitor progress = SubMonitor.convert(monitor);
Thread thread = new Thread() {
#Override
public void run() {
Display.getDefault().syncExec(new Runnable() {
public void run() {
viewer.setInput(ResourcesPlugin.getWorkspace().getRoot()); // this will make the table provider initialize the external source.
}
});
}
};
thread.start();
while(thread.isAlive()) {
progress.setWorkRemaining(10000);
progress.worked(1);
}
progress.done();
}
};
try {
getContainer().run(false, false, runnable);
} catch(Exception e) {
throw new Exception("Could not access data store", e);
}
}
This method gets then invoked when the wizard page's setVisible()-method is called and should, after a couple of seconds, set the viewer's input. This, however, never happens, because the inner-most run()-method never gets executed.
Any hints on how to deal with long-running (where an exact estimate is not available) initializations in Eclipse wizards would be very appreciated!
I have given below a simple example on how to use IRunnableWithProgress along with a ProgressMonitorDialog to perform a task of unknown quantity. To start with, have an implementation to IRunnableWithProgress from where the actual task is performed. This implementation could be an inner class.
public class MyRunnableWithProgress implements IRunnableWithProgress {
private String _fileName;
public MyRunnableWithProgress(String fileName) {
_fileName = fileName;
}
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
int totalUnitsOfWork = IProgressMonitor.UNKNOWN;
monitor.beginTask("Performing read. Please wait...", totalUnitsOfWork);
performRead(_fileName, monitor); // This only performs the tasks
monitor.done();
}
}
Now, a generic implementation to ProgressMonitorDialog can be created as below which could be used for other places where a progress monitor dialog is required.
public class MyProgressMonitorDialog extends ProgressMonitorDialog {
private boolean cancellable;
public MyProgressMonitorDialog(Shell parent, boolean cancellable) {
super(parent);
this.cancellable = cancellable;
}
#Override
public Composite createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
setCancelable(cancellable);
return container;
}
}
Having got the required implementation, the task can be invoked as below to get it processed with a progress dialog.
boolean cancellable = false;
IRunnableWithProgress myRunnable = new MyRunnableWithProgress(receivedFileName);
ProgressMonitorDialog progressMonitorDialog = new MyProgressMonitorDialog(getShell(), cancellable);
try {
progressMonitorDialog.run(true, true, myRunnable);
} catch (InvocationTargetException e) {
// Catch in your best way
throw new RuntimeException(e);
} catch (InterruptedException e) {
//Catch in your best way
Thread.currentThread().interrupt();
}
Hope this helps!
I assume the reason why it's "not working" for you is that the preparation of input is done in UI thread meaning that the progress bar cannot be updated. A better approach is to prepare input in advance and only set input to viewer after that.