So, I have the code below inside an AsyncTask and want to call 7 different asynchronous HTTP requests. All works well, all the 7 execute() methods start at the same time (give a take a few millis, which is great).
Unfortunately, the time it takes with this method is aprox. 16 secs. If I exclude all executor stuff and call the HTTP download methods on the original worker Asynctask, it takes aprox. 9 secs. So, it actually takes less time in sequential order rather than concurrent. Any ideas why this is happening ? Maybe something on the server side ? Maybe because the executors were started on an Asynctask ? Thanks a lot !
MyExecutor executor = new MyExecutor(7, 7, 40000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(new Runnable()
{
#Override
public void run()
{
try {downloadSplashScreenJsonData();}
catch (Exception e)
{
Log.e(TAG, "Could not download splashscreen data.");
e.printStackTrace();
}
}
});
// after another 6 executor.execute() calls,
executor.shutdown();
executor.awaitTermination(40000, TimeUnit.MILLISECONDS);
class MyExecutor extends ThreadPoolExecutor
{
public MyExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
prestartAllCoreThreads();
// TODO Auto-generated constructor stub
}
#Override
public void execute(Runnable command) {
super.execute(command);
Log.e(TAG, "execute()");
Log.e(TAG, "no of thr: " + getActiveCount());
}
}
Don't know offhand, but I observe:
What is restartAllCoreThreads, and why are you calling it in a constructor? Don't start
threads before you need them (and a LinkedBlockingQueue<> will save you space).
Do you really need to run this in an AsyncTask? The threads in a Threadpool don't run on
the UI thread, and running off the UI thread is the main advantage of AsyncTask. If you
really want to do all of this in the background, use an IntentService.
As I look back on this matter, I want to add some more info.
First off, the use case that was required by the application was very retarded and cumbersome (but hey, clients, what can you do...). So like Joe stated above, I wouldn't download data on Asyncs in a million years now. One should use some sort of Service for downloading the data required, if possible.
Secondly, I ended up using RoboSpice library (it also provides caching) instead of Asyncs. It's still not as good as running on a Service, but it's much more well optimised than the barebone version. Might wanna check that out.
Related
I know Android UI is not really meant for executing functions and waiting for them to finish, however, I think there are use cases were it is required, like networking.
My problem is, I want to run a series of network operations that rely on each other and take a bit more time than the split second it takes to the next execution, so some waiting is in order:
Start hotspot
Get network interfaces and IP
Start socket
Initially I tested that all is working using buttons, then it waited between my button presses. But now I'd like to automatize it. I googled but all I found are solutions with Async task, which is deprecated. I tried with threads and join, but that usually causes weird crashes in the runnable, and it is not very elegant. I wonder if there is another solution?
The best thing you can do with SDK it's use Executors to run your work in background sequentially
val newSingleThreadExecutor = Executors.newSingleThreadExecutor()
newSingleThreadExecutor.execute {
// 1...
}
newSingleThreadExecutor.execute {
// 2...
}
But if you want to touch the UI from background should create handler check if view's not null
val handler = Handler(Looper.myLooper()!!)
newSingleThreadExecutor.execute {
handler.post {
view?.visibility = View.GONE
}
}
How about something like this?
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startHotspot();
getNetworkInterfaceAndIP();
startSocket();
}
}, 300);
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.
Note: The app I am working on is for PERSONAL use only. I am trying to collect data for my master thesis.
I am trying to start more than 128 AsyncTasks at once, which fails because of the ThreadPoolExecutor. I've seen some answers why it is not working, but no real answer of how to implement it correctly.
As I have a lot of time for uploading my stuff I was considering to just put my MainActivity to sleep before starting the next upload, which does not seem to work as well.
for (IrisResult s : results) {
try {
Thread.sleep(1000);
mAzureTableManager.addIrisResult(s);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The method addirisResult() actually starts the AsyncTask by protected Void doInBackground(Void... params) {
I am looking for the SIMPLEST solution, not for the best approach!
yourAsyncTask.executeOnExecutor(yourThreadPoolExecutor, params);
And increase your pool size:
yourThreadPoolExecutor.setMaximumPoolSize(size);
Sets the maximum allowed number of threads. This overrides any value set in the constructor. If the new value is smaller than the current value, excess existing threads will be terminated when they next become idle.
android.developer.com - ThreadPoolExecutor#setMaximumPoolSize(int)
android.developer.com - AsyncTask#executeOnExecutor(Executor, Params...)
as an example:
yourThreadPoolExecutor = Executors.newCachedThreadPool();
yourThreadPoolExecutor.setMaximumPoolSize(256);
yourAsyncTask.executeOnExecutor(yourThreadPoolExecutor, params);
I have an Android application that uses AsyncTasks to make get and post calls to send and retrieve data from server. All works fine but sometimes the async task takes a lot of time to execute and thus other async tasks have to wait (if more than 5 async tasks is there) so what will be the best alternative or how to increase the thread pool if it is safe to do so.
Asynctask are implemented behind the scene using threadpool, the default pool size for asynctasks is 1(so you can't run 2 asynctasks in parallel).
In newer versions of android the default Asynctask pool size is 5.
It's possible to change it but not recommended.
You can just create thread like in the sample I attached before:
Thread thread = new Thread() {
#Override
public void run() {
try {
//Do http request here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
I've created an AsyncTask that loads messaging history from a database and then shows it on the device screen:
private void loadHistoryFromDB(Date lastUpdateDate)
{
final class DBAsyncTask extends AsyncTask<Void, Void, List<XMPPMessage>>
{
#Override
protected List<XMPPMessage> doInBackground(Void... arg0)
{
List<XMPPMessage> messages = null;
try
{
messages = PersistenceManager.getXMPPMessagesFromDB(userInfo, 0, messagingActivity);
}
catch (SQLException e)
{
e.printStackTrace();
}
catch (LetsDatabaseException e)
{
e.printStackTrace();
}
return messages;
}
It seems to work fine, but after being executed, it leaves 2 running threads and I can't finish the activity because of that. How can I fix it?
As long as your tasks are executing properly (exits from onPostExecute), this shouldn't be something you have to worry about. Once executed, AsyncTask thread(s) will stick around for possible reuse in the form of a thread pool or single thread, depending on platform version. This is normal behaviour - they will eventually be cleaned-up/reused.
First off, make sure you are calling super.doInBackGround() at the top of your overridden method call.
If that isn't it, it's likely because you are maintaining the connecting to the database.
That is, you still have a lock established on the database.
See if you can explicitly unlock the database, that may fix your problem.
You could put it in the onPostExecute() method.
This problem is most likely due to confusion surrounding the cancel method of AsyncTask.
You need to break down your background task into loopable segments, then Before each loop iteration starts doing your task,you need to check if the task is cancelled and if it is you need to break the loop. There doesn't seem to be any other way to stop an AsyncTask from executing.
I've posted a detailed guide to this problem with code examples here:
http://tpbapp.com/android-development/android-asynctask-stop-running-cancel-method/