Android background threading - android

I'm making image processor app. I need to scan the phone for pictures and list them with their number of pixels. So that's gonna be a a large impact on performance and as I understood, I need to make it work on background thread.
So my question is, what is the best approach for this? I understand that IntentService may be the best solution, but I'm not sure how I will implement progress bar with it, and I need to return Picture objects and later update the UI on shuffle button. I'm doing update with Glide library so that's gonna go smooth.
Reading about Asynctasks, I stumbled about comments how it's bad and leads to leaks in memory and should avoid using it. rXJava is too complicated at the moment.
This is my code:
Main activity:
#OnClick(R.id.shuffle)
public void shuffleList() {
Collections.shuffle(listOfImageFiles);
recyclerViewAdapter = new PictureRecycleViewAdapter(listOfImageFiles, this);
recyclerView.swapAdapter(recyclerViewAdapter, false);
recyclerViewAdapter.notifyDataSetChanged();
}
#OnClick(R.id.scan)
public void processImages() {
//progress bar
listOfPictures = new ArrayList<>();
//Gets data from default camera roll directory. Note that some of the phone companies have different file paths. So instead of hardcoding string paths, I used this instead.
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath();
File filePath = new File(path);
listOfImageFiles = scanPhotos(filePath);
// async?
for (File file : listOfImageFiles
) {
Bitmap bitmap = BitmapFactory.decodeFile(file.getPath());
//int is sufficient for most today's pixels. long would be overkill - 4 vs 8 bytes
int pixels = bitmap.getHeight() * bitmap.getWidth();
listOfPictures.add(new Picture(file.getPath(), pixels));
}
}
public List<File> scanPhotos(File directory) {
List<File> listOfPictures = new ArrayList<>();
try {
File[] files = directory.listFiles();
for (File file : files
) {
if (file.isDirectory() && !file.isHidden()) {
listOfPictures.addAll(scanPhotos(file));
} else {
if (file.getName().endsWith(".jpg") || file.getName().endsWith(".jpeg") || file.getName().endsWith(".png")) {
listOfPictures.add(file);
}
}
}
} catch (Exception e) {
Log.e(e.getMessage(), e.getMessage());
}
return listOfPictures;
}

IntentService
IntentService is definitely a valid approach. You can use Broadcasts to return your result to another component of the app, be it Activity or another Service, for example:
Start the IntentService - if you need some parameters, place them in the Extras of the service intent.
Your IntentService runs on the background thread until the computation is finished.
Upon finishing, send a broadcast with computation result placed in intent extras.
In your activity, register a BroadcastReceiver that will listen for your computation result broadcast.
Upon getting the broadcast in your Activity, retrieve the computation result from intent extras.
You might also implement broadcasts received by your Service for things like cancellation of the computation or updating the parameters.
One of the advantages of IntentService is that you can easily integrate it with the JobScheduler API to defer execution until certain system conditions are met.
Alternatives
You can use a bus library, such as https://github.com/greenrobot/EventBus to communicate between Activity and Service - the only problem is, EventBus won't work with remote services (running in a separate process).
Like you've mentioned, using RxJava with IO and computation schedulers is also a good idea.
AsyncTask is fine as long as you not tie it with a hard reference to an activity - don't implement it as an inner class of Activity and if you want to communicate the result back, do it through a WeakReference<T>

AsyncTask is fine, you just need to be careful with its implementation.
However, for longer running tasks there are better options. IntentService is a good option.
When it comes to a responsive UI when using an IntentService you could add two things.
Notifications
Create an ongoing notification that indicates that your App is working on something. This lets users know that their CPU cycles are being eaten by something in the background and they are less likely(?) to be confused and cranky about their device running slower.
Additionally, it gives your App more of an allowance for staying alive when Android is looking for background Apps to kill to release memory.
EventBus
You can make UI reporting extremely simple by using an EventBus library. I am personally a fan of greenbot/EventBus, but there are others.
Example
In your Activity:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onProgressEvent(ProgressEvent event) {
mProgressBar.setProgress(event.value);
}
In your IntentService:
EventBus.getDefault().post(new ProgressEvent(5000));

Related

Android Firebase Jobdispatcher not starting

Hi Android geeks over there,
I am developing an application which uses 'com.firebase:firebase-jobdispatcher:0.8.5' to schedule jobs. But the jobs are not getting executed in the tested device.
While I checked the dumpsys activity service GcmService I got the following log, in which my job is marked as Not yet run.
What would be the possible reason for this behavior?
I also found a status like READY_BATTERY_LOW, is it because my devices is running low on battery? But while the testing is taking place, the device is having 58% battery.
Also, the device is connected to Jio 4g network.
The dumpsys log is included below, could anyone have some comments to give a light on the issue. :)
(scheduled) com.mypackage.testapp/com.firebase.jobdispatcher.GooglePlayReceiver{u=0 tag="test-sync-job" trigger=window{start=300s,end=360s,earliest=-459s,latest=-399s} requirements=[NET_ANY] attributes=[RECURRING] scheduled=-759s last_run=N/A jid=N/A status=READY_BATTERY_LOW retries=0 client_lib=FIREBASE_JOB_DISPATCHER-1}
Not yet run.
Thanks in advance :)
Here is the bit of making a vocation.
Driver = new GooglePlayDriver(context);
firebaseJobDispatcher = new FirebaseJobDispatcher(driver);
Occupation constraintReminderJob = firebaseJobDispatcher.newJobBuilder()
.setService(ReminderService.class)
.setTag(REMINDER_JOB_TAG)
.setConstraints(Constraint.DEVICE_CHARGING)
.setLifetime(Lifetime.FOREVER)
.setRecurring(true)
.setTrigger(Trigger.executionWindow(
REMINDER_INTERVAL_SECONDS,
REMINDER_INTERVAL_SECONDS + SYNC_FLEXTIME_SECONDS
))
.setReplaceCurrent(true)
.assemble();
firebaseJobDispatcher.schedule(constraintReminderJob);
How about we investigate the above scrap.
Occupation
There are a few ascribes to make an occupation.
A string label that (inside your application) particularly recognizes the Job.
A JobService subclass that will contain all the business rationale identified with the Job.
A JobTrigger will establish that the made Job is presently prepared to execute.
An arrangement of Constraints is required keeping in mind the end goal to execute the made activity. As a matter of course, it is unfilled which implies that Job will be kept running when the JobTrigger is initiated.
A RetryStrategy is in charge of taking care of the disappointment conditions. The default is taken care of utilizing exponential backoff procedure.
A lifetime that indicates the season of the activity in which it ought to stay planned. The
default is to keep the Job planned until the following boot.
Package is for client provided additional items. This is a discretionary parameter.
A boolean demonstrates whether the Job should rehash or not. The default is false which implies that the planned Job will execute just once.
A boolean shows whether the booked Job ought to supplant any prior Job
with a similar tag or not. The default an incentive for this boolean banner is false.
Once your activity is prepared, you can utilize plan() strategy to plan the activity.
open static void scheduleJob(Context setting) {
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
Occupation work = createJob(dispatcher);
dispatcher.schedule(job);
}
ReminderService.class
open class ReminderService broadens JobService {
/**
* This asynctask will run a vocation once conditions are met with the imperatives
* As soon as client gadget gets associated with the power supply. it will produce
* a warning demonstrating that condition is met.
*/
private AsyncTask mBackgroundTask;
#Override
open boolean onStartJob(final jobParameters) {
mBackgroundTask = new AsyncTask() {
#Override
ensured Object doInBackground(Object[] objects) {
Setting = ReminderService.this;
ReminderTasks.executeTasks(context, ReminderTasks.ACTION_CHARGING_REMINDER);
Log.i("TAG", "onStartJob");
return invalid;
}
#Override
secured void onPostExecute(Object o) {
/* false means, that activity is finished. we would prefer not to reschedule it*/
jobFinished(jobParameters, false);
Log.i("TAG", "onStartJob-OnPost");
}
};
mBackgroundTask.execute();
return genuine;
}
#Override
open boolean onStopJob(JobParameters jobParameters) {
on the off chance that (mBackgroundTask != invalid) {
mBackgroundTask.cancel(true);
}
Log.i("TAG", "onStopJob");
/* genuine means, we're not done, if you don't mind reschedule */
return genuine;
}
}
There are three strategies that will be utilized while utilizing FireBase Job Dispatcher.
onStartJob(JobParameters params)- This is the underlying strategy that will be conjured when a vocation is called. It keeps running on the fundamental string. It will restore a Boolean which tells whether an occupation is remaining or not. Returning genuine demonstrates that more work is remaining. We can call jobFinished() when the activity is finished.
onStopJob(JobParameters params)- This technique is considered when your activity is halted. The activity can be halted because of different reasons if the running limitations related to the activity are never again fulfilled. It will restore a Boolean which tells whether work ought to be attempted again or not. On the off chance that returned genuinely, at that point, the system will set up this activity again for execution.
jobFinished(JobParameters params, boolean needsReschedule)- When work has been offloaded to another string, it ought to be called expressly.

Save event type logs

We want to add a reporting feature to our existing application.
For this purpose we are sending Events in JSON via HTTPS to a server application.
We need to remember Event-objects that could not be send to the server (No internet, server not reachable...). We are considering to store the events in a SQLite database and discard all Events that are older than 24 hours to prevent flooding our storage.
Another option would be to write the JSON-objects to a file and concat each new event when it could not be send to the server. The problem with this solution is, that it would be hard for us to discard logs older than 24 hours.
We store the event sin a table with the columns:
| id | json | created_at |
Can anyone recommend best practices for this use case?
Currently we tend to use the sqlite solution but we are wondering if there are any caveats that we are not aware of.
If you don't mind using third-party lib i can recommend android-priority-jobqueue. You can easily achieve what you are trying to do. You can always create job and it will handle itself. You can set if it needs network, if it is persistent (saved into DB when no network) and even you can customize your own retry logic.
Here's little example.
public class PostTweetJob extends Job {
public static final int PRIORITY = 1;
private String text;
public PostTweetJob(String text) {
// This job requires network connectivity,
// and should be persisted in case the application exits before job is completed.
super(new Params(PRIORITY).requireNetwork().persist());
}
#Override
public void onAdded() {
// Job has been saved to disk.
// This is a good place to dispatch a UI event to indicate the job will eventually run.
}
#Override
public void onRun() throws Throwable {
// yours code here
}
#Override
protected RetryConstraint shouldReRunOnThrowable(Throwable throwable, int runCount,
int maxRunCount) {
// An error occurred in onRun.
return RetryConstraint.createExponentialBackoff(runCount, 1000);
}
}
And you call it like this.
jobManager.addJobInBackground(new PostTweetJob("It works"));
use JobService(Android 5+ - lollipop and above) and AlarmManager (for android sdk<21 - pre lollipop) with this solution u can schedule any task and it would be performed. JobService was developed rxactely for tjis purposes(schedule and perform different tasks) maybe you can try JobIntentService it is would work on kitkat(android 4+) devices
P.S.
In that case you didnt need any third party libs and other dependrncies like firebase/google play services(like for FirebaseDispatcher)

Is using Executors.newSingleThreadExecutor recommended in app widget

Currently, in my main app, I am sending multiple texts to status bar object.
My status bar object, is going to display multiple texts sequentially, with sleep time of N seconds for each display interval.
Here's my implementation in my main app.
public synchronized void setNextText(final CharSequence text) {
if (executor == null) {
executor = Executors.newSingleThreadExecutor();
}
executor.execute(new Runnable() {
#Override
public void run() {
Fragment fragment = getTargetFragment();
if (fragment instanceof OnStatusBarUpdaterListener) {
((OnStatusBarUpdaterListener)fragment).setNextText(text);
try {
// Allow 1 seconds for every text.
Thread.sleep(Constants.STATUS_BAR_UPDATER_TIME);
} catch (InterruptedException ex) {
Log.e(TAG, "", ex);
}
}
}
});
}
Now, I would like to have the same behavior in app widget. I was wondering, is using Executor being recommended in app widget environment? If not, what class I should use to achieve the similar objective?
I do have experience in using HandlerThread + AlarmManager in app widget. It works good so far. However, the operation done by the runnable is one time. It doesn't sleep and wait.
The following is the code which I use to update stock price in fixed interval.
// This code is trigger by AlarmManager periodically.
if (holder.updateStockPriceHandlerThread == null) {
holder.updateStockPriceHandlerThread = new HandlerThread("updateStockPriceHandlerThread" + appWidgetId);
holder.updateStockPriceHandlerThread.start();
holder.updateStockPriceWorkerQueue = new Handler(holder.updateStockPriceHandlerThread.getLooper());
holder.updateStockPriceWorkerQueue.post(getUpdateStockPriceRunnable(...
}
However, I have a feeling that, for use case "display multiple texts sequentially, with sleep time of N seconds for each display interval", AlarmManager might not be a good solution. Imagine I have 100 texts. Having to set 100 alarms for 100 texts doesn't sound good...
An AppWidgetProvider is a subclass of BroadcastReceiver. Once your callback (e.g., onUpdate()) returns, your process can be terminated at any point.
If that is not a problem — if you fail to finish the semi-animation that you are doing, that's OK — using an Executor from onUpdate() could work.
If you want to make sure that the text changes go to completion, delegate the app widget updating to a Service, where you use your Executor. Call stopSelf() on the Service when you are done, so it can go away and not artificially keep your process around.
Well the singleThread instance work creates an Executor that uses a single worker thread. meaning only thread to process your operation. But in you case use at least two. Your operations sounds expensive.
To conclude your question stick with the executor service as it thread safe.

Emulate Web Workers in Android pre- Kitkat

Since Webworkers is only implemented from Android 4.4 onwards, is it possible to have a wrapper in the application code that provides this functionality to the contained WebView?
An example on how to solve this would really help.
Thanks,
Rajath
I guess you are talking about running a javascript code block in the background, i.e. different thread. Had tried doing that using RhinoJS on Android. Tested on Android 2.2 and above
https://github.com/devthon/SilentJSAndroid
The main features are
Execute Javascript code without browser context
Execute Javascript code from a script file
Load other JS files in the same context
Execute a method in the background thread and return a result
Execute a Object.Method() call
Execute a prototype method call
Run long running script in the background after app is closed.
May not be a full fledged Web worker as such, since it doesn't have API to check the status in between. But that can be still added to the interface I believe.
If this is the direction you are looking for, I can explain more on how it is done.
How much of the Worker spec do you need to implement, and how flexible does the implementation need to be? You could probably get basic functionality up and running using a JavaScript interface[1] and spawning threads natively from Java. However this will get complex quite quickly.
Perhaps if you can describe what you are using workers for I might be able to offer a different/better suggestion.
[1] http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)
--
Adding some pseudo code
In JavaScript spawn a Java worker thread:
var worker_id = window.Android.spawnWorker();
In JavaScript, run a task on that worker:
var task_id = window.Android.doAdditionOnWorker(2,2, worker_id);
Handle the result in JavaScript
function onReceiveResultForWorkerTask(task_id, result) {
alert("the answer was " + result);
}
Java side:
public int spawnWorker() {
HandlerThread worker = new HandlerThread();
worker.start();
Handler h = new Handler(worker.getLooper()) {
#Override
handleMessage(Message msg) {
switch(msg.what)
case ADD:
// calculate the answer and send back to JS via UI thread
// Unpack parameters and task id from Message
mWebView.post(new Runnable(
public void run() {
mWebView.loadUrl("javascript:onReceiveResultForWorkerTask(task_id, " + (a+b) +");");
}
)
}
};
mWorkerMap.put(mWorkerId++, h);
return mWorkerId;
}
public int doAdditionOnWorker(int a, int b, int worker_id) {
Handler h = mWorkerMap.get(worker_id);
Bundle b = new Bundle();
int task_id = mTaskId++;
// pack arguments and task_id into the bundle
h.postMessage(Message.obtain(h, ADD, b);
return task_id;
}
Don't forget to go through and tear down all the worker threads that you spawn when the app doesn't need them anymore. Depending on how many workers you need you might also prefer to use a thread pool rather than creating new threads every time.

How to initialize handlers from separated threads?

I am coding an application where a remote service has to run at all time and to perform these taks :
Create and keep a bluetooth connection to another device
Ask this device for informations periodically (1 second)
Get GPS Location periodically (1 second)
Write previous datas in a text file every 1 second
For this, I created from my remote service 2 Threads : one for the data request (loopThread) and one for the GPS Location (gpsThread). The loopThread, after getting the datas from the blueTooth Device should ask the gpsThread for the location. It has to be very quick, that's why I am using a Thread, so i can store the Location in a variable which can be sent.
The remote serviceand the 2 threads should communicate through handlers.
The problem is : I can make each Handlers communicate with the remote service, but not with each other.
I create Threads like this :
myGPSThread = new GPSThread(mainServiceHandler,locationManager);
myLoopThread = new AcquisitionThread(mainServiceHandler, sockIn, sockOut);
I tried sending the Handler of one to the other by message, but Handlers seem not to be parcelable.
Does anyone have the solution to this?
If you want to stick to your Handler based approach, you can set up your two Threads as follows.
For your Threads, subclass HandlerThread instead of Thread. Also, make them implement Handler.Callback and don't start() them right away.
final class GPSThread extends HandlerThread implements Handler.Callback {
private Handler otherThreadHandler;
public void setOtherThreadHandler(Handler otherThreadHandler) {
this.otherThreadHandler = otherThreadHandler;
}
#Override
public void handleMessage(Message msg) {
// like in your comment
}
}
myGPSThread = new GPSThread(locationManager);
myLoopThread = new AcquisitionThread(sockIn, sockOut);
myGPSThreadHandler = new Handler(myGPSThread.getLooper(), myGPSThread);
myLoopThreadHandler = new Handler(myLoopThread.getLooper(), myLoopThread);
myGPSThread.setOtherThreadHandler(myLoopThreadHandler);
myLoopThread.setOtherThreadHandler(myGPSThreadHanlder);
myGPSThread.start();
myLoopThread.start();
If you want low latency and your event-driven code is short and friendly, you may want to create the HandlerThreads with a better-than-default priority; see here.
As already mentioned, you can as well set up two "ordinary" Threads which operate on two LinkedBlockingQueues; these Threads would block in their run() methods upon waiting for a message (aka Object) from the other Thread.

Categories

Resources