RoboSpice and android life cycle trouble - android

I use robospice like this:
ProjectInfoRequest request = new ProjectInfoRequest(mProfile);
spiceManager.execute(request, PROJECT_INFO_LISTENER);
It downloads data and almost everything is ok.
However there are some things that makes me unhappy:
When I press home button, SpiceManager.shouldStop() is called accordingly to the documentation. But when the task is executed listener does not get call, which is right(I guess, because the activity may be destroyed by OS) but how do I save downloaded data? I don't see any in-memory persister in 1.4.0 version
When I try to specify cacheKey like this
spiceManager.execute(request, "projectInfo", DurationInMilis.NEVER, PROJECT_INFO_LISTENER);
the request won't even start executing. However I really need it cause i'd like to use addListenerIfReqeustPending method. What are posible reasons not to start execute request?

Which version do you use ? 1.4.1 has just been released. And which service do you use ? Which cache manager is used by the SpiceService ?

Related

Android Work Manager: Can I force prune the Completed Jobs?

I am uploading photos in my app and want to provide the User with the upload progress. The way I was going to do this is have a global tag, UPLOAD_MEDIA_TAG and use that whenever I am creating a OneTimeWorkRequest. That way I can just observe the WorkManager.getInstance().getStatusesByTag(UPLOAD_MEDIA_TAG) LiveData, and whenever a job completes I would show a percent completed. (I.E. Uploading 3/10 photos would show 30%). Then once all 10/10 photos have been uploaded, I would hide the progress bar. This works great as it easily supports leaving the app, coming back, and you will see the Progress Bar as soon as the app launches right where they left off.
The problem is that once all 10/10 jobs are finished and marked as completed, those jobs will stick around until the WorkManger prunes them. So if the user uploads 5 more photos, the LiveData is returning 15 statuses instead of 5, throwing off the percent calculation.
I noticed there is a method OneTimeWorkRequest.keepResultsForAtLeast(duration) but what I would want is something like, keepResultsForAtMost(duration) or a WorkManager.getInstance().forcePrune() method that would cleanup all the completed jobs from the database.
Any help would be great!
After submitting an issue with Google, they are saying there will be a function called, pruneWork in Alpha03.
As of alpha release, you don't have much control over job pruning since it is managed by WorkManager. You can however observe the lifecycle of WorkManager to get job status and take necessary action as follows:
WorkManager.getInstance().getStatusById(myWork.getId())
.observe(lifecycleOwner, workStatus -> {
// Do something with the status
if (workStatus != null && workStatus.getState().isFinished()){
// Stop observing data or do other action
}
});
Note:
Use [WorkManager 1.0.0-alpha03 which has several bugs fixed and new features introduced. One you might be interested is:
Added WorkManager.pruneWork() to remove completed jobs from the internal database

Updated RealmResults with time-based query

I'm starting to approach this wonderful world of Realm. I'm very happy of the results I'm getting and now I have one question to submit.
In my android app I've got a Fragment that displays data retrieved from Realm. The query condition is that the time this data refers to is in between the beginning and the end of today.
RealmResults<Appointment> results = realm
.where(MyObject.class)
.between("begin", rangeBegin, rangeEnd)
.between("end", rangeBegin, rangeEnd)
.findAllSorted("begin", Sort.ASCENDING);
This query is executed in the onStart() method helping me to exploit the live-update feature, which indeed works very well.
I've also added listeners for changes in order to optimize UI updates.
Now the question is: how does this live-update behave if the time conditions change? (Imagine I keep the app opened for more than one day without touching it or simply I keep the app opened for minutes around midnight)
From what I've seen it seems to do the same query done the very first time onStart() was executed.
Is there a way to have also live-updating query or should I re-run that query somewhere else outside onStart()?
Thank you in advance
Now the question is: how does this live-update behave if the time conditions change? (Imagine I keep the app opened for more than one day without touching it or simply I keep the app opened for minutes around midnight)
The query is pretty constant after you've set it up, so you'd need to execute a new query with different parameters for rangeStart and rangeEnd, and replace your other results.
This query is executed in the onStart() method helping me to exploit the live-update feature, which indeed works very well. I've also added listeners for changes in order to optimize UI updates.
Personally I'd advise to put the query in onCreateView() instead, and the Realm lifecycle management to onCreateView() and onDestroyView().
Also, you can avoid manually assigning RealmChangeListeners for displaying lists if you use RealmRecyclerViewAdapter (adapters 1.3.0 works with realm 1.2.0).
If you use RealmRecyclerViewAdapter, then just call adapter.updateData(newResults); and it'll update the view as needed.

Updating visual components in android embarcadero c++builder

I need to update several visual components in my app during a timeconsuming function, instead my app seems to hang during this function call, rather than update the visual components on the screen. When the function exit, I see only the last changes to the components.
Is there a simple way to do the updates, or do I need to create a parallel process and have a 'timer' to read the data simultaniously (using semaphores) and present them in the timer call ?
Any suggestions ?
I asked the same question yesterday here. Like mh taqia said you can use Application->ProcessMessages() but you have to be careful with it. For my application, it worked but look at some posts about the function first.
I tried following:
MainForm->Invalidate();
MyControlRoot->Repaint();
MyControlRoot is a control containing somewhat 50-60 different other controls
But MyControlRoot wouldn't repaint with this method. ..
Despite the warnings from you Remy, I tried Application->ProcessMessages();
...works for now...
By the way... I cannot see any warnings in Docwiki on using ProcessMessages... what could I expect?
RG

Best practice to use AsyncTask in autocomplete?

I am using Async task to populate auto-complete suggestions from server.
Problem:
when user types and removes the text in edittext so many times.
lets say he typed: cofee > cof > coffee >coffee late .... etc for so many times.
for each text changed after 3 keyword(threshold) i am initializing an asynctask and ask for result.
so in current scenario i have so many threads running in background. so some of my latest async threads are waiting for there chance.
Whole this make my app very slow.
What can I do to tackle this problem?
If it is possible to load entire data from server at beginning...then you can avoid calling asynctask repeatedly and fetching the data from server. This will improve performance of you app. If data displayed in Listview is String, following link show how to filter it:
http://www.androidhive.info/2012/09/android-adding-search-functionality-to-listview/
And if custom object is used in ListView adapter, try:
Filtering ListView with custom (object) adapter
Hopefully this helps.
You should cancel the current task before issuing a new one. Use AsyncTask#cancel(true) for that and make sure that the execution of the task can be quickly stopped. This means correct handling of interruption and frequent checking whether the task was cancelled in the body of AsyncTask#doInBackground.
And you cannot execute again the AsyncTask you have cancelled. You have to create a new one. (Trying to execute it again leads to IllegalStateExceptions)
It worked for me by cancelling the task each time you change the text (if it is still running).
You need to define your request once outside the listener(private for the class), and then start your listener function by (if your request is not finished, then cancel it).
define your request out side the function
private YourSearchTaskClass YourTaskReq = new YourSearchTaskClass();
then start your addTextChangeListener/afterTextChanged by this
if (YourTaskReq.getStatus()!= AsyncTask.Status.FINISHED)
YourTaskAvReq.cancel(false);
YourTaskReq= new YourSearchTaskClass(keyword);

What is a good way to call a method from the main game loop via a scheduled alarm?

I'm using libgdx for a game, and I want to be able to have the game call an update() method that is set up right now to get called every 15 minutes. However, this only works of course when the game itself is open, and I want this to work as long as the device is on.
So far I figured out how to create the BroadcastReceiver and use AlarmManager to call it every 15 minutes, and I know how to set it up to add my alarm in on boot. The only thing I have to figure out is how to have that scheduled on exact 15 minute intervals(i.e. 9:30,9:45, etc.)
This is the source for the AndroidApplication:
https://github.com/libgdx/libgdx/blob/master/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidApplication.java
And the code used to start it is like this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration();
cfg.useGL20 = true;
cfg.useAccelerometer = false;
cfg.useCompass = false;
initialize(new MainClass(), cfg);
}
Looking around can't see to find any way of actually referencing the MainClass() without calling onCreate(). I'm assuming the best way to do something like this have a separate intent with a copy of the update() method and access to the same data be called instead, however I don't know how to do that in libgdx.
I think you are trying to make your game class do too much, not to mention this will run into problems when you're "alarm" fires and the game is not running so nothing could receive the call to update(). If what you really need is a way to periodically update some data for your game outside of your running game loop I would approach it like so:
Create your AlarmManager as you have, but instead of trying to reach into your existing game class and call update, just store of the updates to a SharedStorage location. {Android Docs}
Create a new Interface in your core project that defines a StoredDataReader.
Create a new class in your android project called AndroidStoredDataReader that implements StoredDataReader, and knows how to read from the stored updates location.
Overload your MainClass() constructor to take in a "StoredDataReader" instance.
In your onCreate() method, you then build up your AndroidStoredDataReader class, and then pass that to your new MainClass() call.
In your game's update/render loop you would then ask the StoredDataReader for the required data.
This would allow you to also take the same approach if you port the application to GWT or desktop, where you can implement the StoredDataReader for each platform. (GWTStoredData reader might read from the browser localStorage, the desktop version might read from a local file, etc)

Categories

Resources