I'm trying to show feedback the percentage of which they have downloaded data from a server.
The flow goes something like this:
LoginActivity
- onSuccess, call Service
to download data
- while Service
is working, I've already switched the user to HomeActivity
HomeActivity
-This activities layout holds a Fragment I created called LoadingFragment
-There is a method in LoadingFragment
that is subscribed
to an event that is posted by the Service
My problem is that the Fragment UI is not changing at all whenever an event has been posted.
I logged everything, and I can see the event posting the correct data but the data is not being reflected on the UI.
Below is my Service
:
@Override
public int onStartCommand(Intent intent, int flags, final int startId) {
Integer id = intent.getIntExtra("id", 0);
//do sync here
Log.i(LOG_TAG, "Make rest call to retrieve all r for id: " + id);
mRestClient.getApiService().getR(id, new Callback<List<R>>() {
@Override
public void success(List<R> rResponse, Response response) {
Integer outstanding = routeResponse.size();
Integer percentage;
LoadingEvent loadingEvent = new LoadingEvent();
SyncEvent syncEvent = new SyncEvent();
Log.i(LOG_TAG, "Callback success r");
System.out.println("yohellotest");
Log.i(LOG_TAG, "Begin insertion");
DaoMaster daoMaster = MyApp.getDaoMaster();
DaoSession session = daoMaster.newSession();
SQLiteDatabase db = session.getDatabase();
RDao rDao = session.getRDao();
WDao wDao = session.getWDao();
JDao jDao = session.getJDao();
Log.i(LOG_TAG, "--Beginning Transaction--");
//db.beginTransaction();
try {
int counter = 0;
for(int i = 0; i < rResponse.size(); i++) {
R r = rResponse.get(i);
rDao.insert(r);
Log.i(LOG_TAG, "inserted r: " + r.getId());
for(int j = 0; j < r.getW().size(); j++) {
W w = r.getW().get(j);
wDao.insert(w);
Log.i(LOG_TAG, "inserted w: " + w.getId());
for(int k = 0; k < w.getJ().size(); k++) {
J j = w.getJ().get(k);
jDao.insert(j);
Log.i(LOG_TAG, "inserted j: " + j.getJId());
}
}
counter += 1;
percentage = (int) Math.floor((double) counter / outstanding * 100);
loadingEvent.setPercentage(percentage);
bus.post(loadingEvent);
}
Log.i(LOG_TAG, "Finished inserting");
//db.setTransactionSuccessful();
} catch (Exception e) {
Log.i(LOG_TAG, "Exception happened " + e.getMessage().toString());
System.out.println("yo something happened, but I don't know what");
} finally {
Log.i(LOG_TAG, "--Closing transaction--");
//db.endTransaction();
}
syncEvent.setIsSuccess(true);
syncEvent.setStatus(200);
bus.post(syncEvent);
}
@Override
public void failure(RetrofitError error) {
Log.i(LOG_TAG, "Rest call failed for this api");
System.out.println("failtests");
}
});
return START_STICKY;
}
Fragment
Subscribed Method
@Subscribe
public void loadingResponse(final LoadingEvent loadingEvent) {
Log.i(LOG_TAG, "Response from loading: " + loadingEvent.getPercentage());
if(getActivity() == null)
return;
textTest.setText(loadingEvent.getPercentage().toString());
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i(LOG_TAG, "Updating ui for loading text" + loadingEvent.getPercentage().toString());
mCircularProgressBar.setProgress(loadingEvent.getPercentage());
textTest.setText(loadingEvent.getPercentage().toString());
}
});
}
When I check my Logs, I see everything coming in fine, but the UI is not reflecting it. What am I missing here?
EDIT Forgot to mention. I'm using this library for my circle progress bar:
EDIT
As of today, I still have yet to figure this out. I also noticed that my adapter is not being updated when the service posts the event. Previously, the context
used to startService()
was the getApplicationContext()
from the LoginActivity
. I thought this might have been a problem so I changed it to get the instance of the HomeActivity
instead. I thought that firing the service from my HomeActivity
would have solved the problem, but I'm still getting the same results unfortunately.
Okay so no one really tried to attempt answering my question but I figured it out.
I actually skimped over the documentation part of the Service
class and didn't know that it was executing on the Main Thread. To fix this, I had to run an AsyncTask
to execute my operation in the background.
The only thing I had to change in my codebase was to move the executing code from the onStartCommand
method into an AsyncTask
. The AsyncTask
will be initiated onStartCommand
and everything should be working fine.
My code looks something like this now :
Service
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
DownloadTask downloadTask = new DownloadTask();
downloadTask.execute();
return START_STICKY;
}
private class DownloadTask extends AsyncTask<Void, Void, LoginEvent> {
@Override
protected LoginEvent doInBackground(Void... params) {
//Code here to run my operations
//Call api, insert to db, post events etc...
//
}
@Override
protected void onPostExecute(LoginEvent event) {
//run anything here you want to do after execution
}
}
You can ignore my LoginEvent
as this was something for my event bus to post events to any subscribers.
Also, keep in mind that if you are going to change any views from this AsyncTask
through the bus
, make sure the subscriber uses the runOnUi
to execute or else you'll hit a runtime exception since you're trying to change a view from something other than the MainThread
.