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.
Related
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.
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));
I made a app the connects to a ble device and receives data from it. I was following this link "http://toastdroid.com/2014/09/22/android-bluetooth-low-energy-tutorial" at the Hints and observation section it says to Queue All GATT operations. How do I do that?
Check out NordicSemiconductors open source project Puck Central, or more specifically the GattManager class, who perfectly demonstrates how to queue all GATT operations.
If you don't want to handle this sort low level bluetooth specifics yourself however, I can recommend the great library RxAndroidBle, which does much of the heavy lifting for you.
To queue the requests you could make a queue class which has an Arraylist of requests.
Every time you want to make a request add it to the queue and start processing the queue (if the queue isn't already being processed). Once you've processed the current item check if there are still items to process and carry on processing them.
You'll also probably need to add a timeout in case one of the requests gets stuck.
Sample code on how you could process a queue using a handler:
private void startProcessingQueue() {
if (queueIsRunning) {
return;
}
queueIsRunning = true;
h.postDelayed(new Runnable(){
public void run(){
processQueue();
if(queue.isEmpty()) {
queueIsRunning = false;
return;
}
h.postDelayed(this, QUEUE_PROCESSING_DELAY);
}
}, QUEUE_PROCESSING_DELAY);
}
This is my first Android application and I am finding troubles with while loop, I am trying to use a while loop on my Android application but the application freezes.
What I'm trying to do is track the user location (using onlocationChanged) and keep querying on the location until the query returns a result. It's a GIS application so I am going to describe the application behavior:
the application keeps tracking the user position using a listener "onLocationChangedListener" and store it in a variable "myPosition". I am using a boolean"noResults=true". I will use a method "query(myPosition)" in the while loop, this method has a callback that when a result is found, and changes a boolean "noResults" to false. the loop will keep on until "noResults" is false (that means query's callback changed the boolean's value)
, here's what I did:
while(noResults)
{
//myPosition keeps changing
query(myPosition);
//query has a callback that when a result is found it changes noResults to false
}
I resolved the problem using a "Handler" that query the Feature Layer every 5 seconds, this stops the main thread from generating application not responding error:
Handler m_handler=new Handler();
Runnable m_runnable;
m_runnable = new Runnable(){
public void run() {
//query code here
m_handler.postDelayed(m_runnable, 5000);
}
};
m_handler.postDelayed(m_runnable, 0);
running while loop codes on the main thread freezes the UI, and makes all other processes pause making your app unresponsive use
Threads..
also note that the while loop you are running is running on a default Thread termed as the ui thread so in short run while loops on separate threads..
eg..
new Thread(new Runnable() {
#Override
public void run() {
// Your hard while loop here
//get whatever you want and update your ui with ui communication methods.
}
).start();
for ui communicating methods
View.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(getActivity(), "updated ui", Toast.LENGTH_LONG).show();
}
});
the view could be any views you are updating..
also like #TehCoder said you could use asynctask but asynctask is not meant for long workaflow work there are 3 of them but i can't recall the last one
Maybe you should use an AsyncTask? I'm not quite sure what your problem is tho.
Loop is not a problem in android (or any language).
There are two scenario might be reason for your freezing,
If you run network call in api, android throw error and crashes. You have to do network related calls in Aysnc Task ot threading
Use try throw catch and exception cases to avoid app crashing and better coding skill.
in the beginning I thought it would be fairly simple, but I guess it's not.
I want to call a URL every 10 minutes, either when the app is in the background or
in the foreground. How can I realize this?
I'd use a Service with a Handler inside. Using directly Threads is another approach but it's more likely it will be killed if the Android OS needs to free memory.
The Handler part would be something like this:
boolean stopHandler = false;
Runnable runnable = new Runnable() {
#Override
public void run() {
// Do whatever you need
...
if (!stopHandler) {
handler.postDelayed(this, 600000); // 10 minutes
}
}
};
In iOS 7 you can schedule background operations for periodically fetching data from the network. This tutorial is an example of scheduling background fetch operations -