I have an activity which is using a postDelayed call:
public class SplashActivity extends Activity {
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(...);
handler.postDelayed(new Runnable() {
public void run() { finish(); }
}, 3000L);
}
}
This runs at app startup, and i need to navigate it and my login screen. However, the UIController's loopMainThreadUntilIdle doesn't seem to take the underlying MessageQueue in the handler into account. As such, this action finishes immediately while there is still messages in the queue.
onView(withId(R.id.splash_screen)).perform(new ViewAction() {
#Override
public Matcher<View> getConstraints() {
return isAssignableFrom(View.class);
}
#Override
public String getDescription() {
return "";
}
#Override
public void perform(final UiController uiController, final View view) {
uiController.loopMainThreadUntilIdle();
}
});
I've been unable to figure out how to block until the queue is drained. Android itself is preventing me from doing a lot of things i would have tried (like extending Handler and overriding the postDelayed method, etc...)
Anyone have any suggestions on how to handle postDelayed?
I'd rather avoid uiController.loopMainThreadForAtLeast, which seems hacky (like a Thread.sleep would)
When Espresso waits, it actually does take in account MessageQueue, but in a different way from what you think. To be idle, the queue must either be empty, or have tasks to be run in more than 15 milliseconds from now.
You can check the code yourself, especially the method loopUntil() in UiControllerImpl.java and the file QueueInterrogator.java. In the latter file you will also find the logic of how Espresso checks the MessageQueue (method determineQueueState()).
Now, how to solve your problem? There are many ways:
Use AsyncTask instead of Handler, sleeping on the background thread and executing actions onPostExecute(). This does the trick because Espresso will wait for AsyncTask to finish, but you might not like the overhead of another thread.
Sleep in your test code, but you don't like that approach already.
Write your custom IdlingResource: this is a general mechanism to let Espresso know when something is idle so that it can run actions and assertions. For this approach you could:
Use the class CountingIdlingResource that comes with Espresso
Call increment() when you post your runnable and decrement() inside the runnable after your logic has run
Register your IdlingResource in the test setup and unregister it in the tear down
See also: docs and sample, another sample
As far as I know there is no wait for activity to finish method in espresso. You could implement your own version of waitForCondition, something robotium has. That way you'll only wait for as long as is needed and you can detect issues with your activity not finishing.
You'd basically poll your condition every x ms, something like.
while (!conditionIsMet() && currentTime < timeOut){
sleep(100);
}
boolean conditionIsMet() {
return "espresso check for if your splash view exists";
}
Related
I am writing an Android application that interfaces with the Motorola EMDK, and I am running into an issue with timing/threading. I have an activity that adds a fragment to perform a very specific function using the EMDK, displays a screen that tells the user what is happening and then is cleaned up by the activity after about 15 seconds.
I am noticing a 1-2 second delay between when the EMDK action occurs, in this case the device cradle is being unlocked, and when the GUI is displayed that says "The cradle is now unlocked."
I have done some research about how Android handles drawing to the screen for fragments, and everything I can find says that onResume is called "when the fragment becomes visible." This does not match my experience, however. According to how I understand the code below should work, the screen should be drawn and then the EMDKManager.getEMDKManager() method is called, which constructs a pointer to the EMDK service and creates a new thread to perform the unlock:
#Override
public void onResume() {
super.onResume();
EMDKManager.getEMDKManager(getActivity().getApplicationContext(), this);
}
It looks more like the screen is drawn to only once onResume() completes in entirety, ie EMDKManager.getEMDKManager() finishes its call as well.
As the fragment is the EMDKListener object that is required for the second parameter for the method, I am struggling finding a way to thread this correctly. I need the GUI to be drawn first or at the same time that the cradle unlock occurs.
Are there any other methods that can be overridden or interfaced with to get the equivalent to an onViewDrawn() event for the fragment?
Thank you very much.
All the lifecycle method onCreate(), onResume() onStop() etc. are called by the main thread, which is also responsible for drawing the UI.
By preforming a long operation in those method, you block the UI thread from handling touch input as well as drawing the app
you can start your long operation on another thread by doing so:
new Thread(new Runnable() {
#Override
public void run() {
// do long operations here
}
}.start();
note that if that operation wants to update the UI components it MUST be done on the UI thread, you can do so by passing a runnable to the activity
activity.runOnUiThread(new Runnable() {
public void run() {
// do UI updating but, do not block it here
}
});
(or you can create an handler if it's a Service or you want to delay those runnables)
Although I have huge concerns about memory use/leaks, I did this in order to get the timing right:
private EMDKManager.EMDKListener getThis() {
return this;
}
private Runnable initEMDK = new Runnable() {
#Override
public void run() {
EMDKManager.getEMDKManager(getActivity().getApplicationContext(), getThis());
}
};
#Override
public void onResume() {
super.onResume();
Log.v(LOGTAG, "Starting");
new Thread(initEMDK).start();
}
I feel like there is a standard way of doing the getThis() method. If you know it, I would love to know.
Thank you.
I've been writing android apps for some months now, and I'm at the point where I'm building an actual needed app.
As I want that to work nice and fast, I made a Workerthread to do all kinds of tasks in the background while the UI can...build up and work and stuff.
It's based on the Android Studio Drawer app blueprint.
In Main.onCreate I got my operator=new Operator(), which extends Thread.
Now, when loading a new Fragment, it sometimes calls MainActivity.operator.someMethod() (I made operator static so I can use it from anywhere), and after some time I realized, the only tasks actually running in background are those in the operators run() method and an Asynctask my login Fragment runs. Everything else the UI waits for to complete and therefore gets executed by the UI thread.
So I thought: no problem! My operator gets a handler which is built in run(), and I change those tasks:
public void run() {
Looper.prepare(); //Android crashed and said I had to call this
OpHandler = new Handler();
LoadLoginData();
[...Load up some Arrays with hardcoded stuff and compute for later use...]
}
public void LoadLoginData() {
OpHandler.post(LoadLoginDataRunnable);
}
private Runnable LoadLoginDataRunnable = new Runnable() {
#Override
public void run() {
if(sharedPreferences==null)
sharedPreferences= PreferenceManager.getDefaultSharedPreferences(context);
sessionID=sharedPreferences.getString("sessionID", null);
if(sessionID!=null) {
postenID = sharedPreferences.getString("postenID", PID_STANDARD);
postenName = sharedPreferences.getString("postenName", PID_STANDARD);
context.QuickToast(sessionID, postenName, postenID);
}
}
};
context is my MainActivity, I gave the operator a reference so I could send Toasts for Debugging.
But now, the Runnables seem to not run or complete, any Log.e or Log.d stuff doesn't arrive in the console.
After some googeling and stackoverflowing, everyone is just always explaining what the difference is between Handlers, Asynctask, and Threads. And the multitask examples always only show something like new Thread(new Runnable{run(task1)}).start times 3 with different tasks.
And so became my big question:
How to correctly, over a longer time (~lifecycle of the MainActivity), with different tasks, use a background thread?
Edit: to clarify, I would also like a direct solution to my special problem.
Edit 2: after reading nikis comment (thank you), the simple answer seems to be "use HandlerThread instead of thread". Will try that as soon as I get home.
Trying a HandlerThread now. It seems my OpHandler, initialized in run(), gets destroyed or something after run() has finished, not sure whats up here (this is btw another mystery of the kind I hoped would get answered here). I get a NullpointerException as soon as I try to use it after run() has finished.
Make your worker thread own a queue of tasks. In the run() method, just pop a task from the queue and execute it. If the queue is empty, wait for it to fill.
class Operator extends Thread
{
private Deque<Runnable> tasks;
private boolean hasToStop=false;
void run()
{
boolean stop=false;
while(!stop)
{
sychronized(this)
{
stop=hasToStop;
}
Runnable task=null;
synchronized(tasks)
{
if(!tasks.isEmpty())
task=tasks.poll();
}
if(task!=null)
task.run();
}
}
void addTask(Runnable task)
{
synchronized(tasks)
{
tasks.add(task);
}
}
public synchronized void stop()
{
hasToStop=true;
}
}
In android why should we use a asyntask and service, instead of using a new thread() and write the necessary background functionality?
I know that we should not run long running operations like downloading a file from server on the mainthread aka UI thread. And should use a asynctask or service.
But why cant we create a new thread() {which is eventually a new thread other than the main thread} and write necessarily long running operation in that thread.
why did google create the AsyncTask and Service without suggesting to use the regular New Thread()???
thanks in advance
edit1:
may be i wasn't clear in my question or not sure, if i am, even now. help me out.
i get it, the whole point starts from
Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread
why ?
1.how much can the UI thread handle ? how can we determine a breakpoint? how is a ANR point determined? can we track?
2. when a service component handles long running operations why can't a activity component handle?
Remember that if you do use a service, it still runs in your application's main thread by default, so you should still create a new thread within the service if it performs intensive or blocking operations
http://developer.android.com/guide/components/services.html
the above statement is from android documentation.
3.why cant a service start in a new thread straight away, if we are so concerned about main thread? don't get me wrong in question 3, i am trying to understand the advantage of starting the service in main thread. by default.
in the above statement , does it suggest the main thread's ability to start and handle a service's long running operation load? if so does it contradict with question 1.
Well let's look how you'd perform a simple task using a Thread.
The first step is to create a Thread using a Runnable. Something like this:
private void fetchResultsAsync() {
Runnable runner = new Runnable() {
#Override
public void run() {
List<String> results = fetchResultsFromWebServer();
}
};
new Thread(runner).run();
}
The thing is, we need to show the results so it would actually be more like this:
private void fetchResultsAsync() {
Runnable runner = new Runnable() {
#Override
public void run() {
List<String> results = fetchResultsFromWebServer();
workFinished(results);
}
};
new Thread(runner).run();
}
private void workFinished(List<String> results) {
// show the results on the UI
}
It looks good, but there's a problem; the callback method (workFinished) has to update the UI. If we do this from any non-main thread, there will be big problems. We need a thread-safe way to call that method, which is what Handlers are for. Let's also throw in a method for updating our progress, which is very common. The code would now look like this:
private final Handler myHandler = new Handler();
private void fetchResultsAsync() {
Runnable runner = new Runnable() {
#Override
public void run() {
List<String> results = fetchResultsFromWebServer();
workFinished(results);
}
};
new Thread(runner).run();
}
private void showProgress(int result) {
myHandler.post(new Runnable() {
#Override
public void run() {
// update a progress bar here
}
});
}
private void workFinished(final List<String> results) {
myHandler.post(new Runnable() {
#Override
public void run() {
// show the results on the UI
}
});
}
Compare this to the implementation using an AsyncTask:
private void fetchWithTask() {
new AsyncTask<Void, Integer, List<String>>() {
#Override
protected List<String> doInBackground(Void... params) {
return fetchResultsFromWebServer();
}
#Override
protected void onPostExecute(List<String> strings) {
// show the results on the UI
}
#Override
protected void onProgressUpdate(Integer... values) {
// update a progress bar here
}
}.execute();
}
It doesn't differ much by lines of code, but it's much more obvious what needs to happen and where. It protects you from nasty mistakes like forgetting to wrap UI-touching code in a Runnable that has to be posted to a UI-Thread-owned Handler.
Now imagine that you have several different types of small background tasks that need to be performed. It would be very easy to call the wrong showProgress or workFinished method from the wrong background Thread because you have to plug all those pieces together yourself.
There's also a very nasty bug lurking in the use of Handler's default constructor. If the containing class is first referenced by a non-UI thread during runtime, the Handler would belong to that Thread. AsyncTask hides always does things on the correct Thread. This is hard to catch!
At first blush AsyncTasks don't seem all that useful, but the callback plumbing is where they really pay off in spades.
"instead of using a new thread() and write the necessary background functionality?"
Why rewrite the background functionality? AsyncTask does it for you. As njk2 mentioned a Service is not really a fair comparison, though IntentService automatically creates a new thread for you in onHandleIntent().
edit: To answer your other questions, blocking the UI thread, will block all user interaction and the app will appear to "freeze". Definitely not something we want to do at all.
while it is very convenient to use, from my understanding, AsyncTask has two important limitations:
doInBackground of any instances will share the same worker
thread, i.e. one long running AsyncTasks can block all others.
execute, onPostExecute and other "synchronizing" methods must/will always be executed on the UI-thread, i.e. not on the Thread, which wants to start the task.
I ran into trouble, when I tried to reuse some existing AsyncTasks in a background IntentService that are responsible for the client-server communication of my app. The tasks of the service would fight over time in the worker thread with those of the UI activities. Also they would force the service to fall back onto the UI-thread, although that service should perform its work quietly in the background.
How would I go about removing/circumventing these limitations? I basically want to achieve:
A framework that closely resembles AsyncTask (because I need to migrate a lot of critical code there).
Each instance of such a task should run its doInBackground on its own thread instead of a single worker thread for all instances.
Edit: Thx to VinceFR for pointing out this can be achieved by simply calling executeOnExecutor instead of execute.
The callbacks like onPostExecute should be called on the same thread that started the task by calling execute, which should not need to be the UI-thread.
I figure, I'm not the first person to require something like this. Therefore I wonder: Is there already some third-party library that can be recommended to accomplish this? If not, what would be a way to implement this?
Thanks in advance!
The solution looks like this:
All classes that spawn AsyncTasks that might interfere with each other get their own Executor like this one (make that elaborate as you like using thread pools etc.):
private Executor serviceExecutor = new Executor() {
public void execute(Runnable command) {
new Thread(command).start();
}
};
As pointed out by VinceFR you can run an AsyncTask on a given Executor by calling it like this (where payload are the parameters that you would regularly pass to a task):
task.executeOnExecutor(serviceExecutor, payload);
However, this breaks backwards-compatibility to Gingerbread and earlier. Also, if you want to support Honeycomb, you need to make sure, this call happens on the UI thread. Jelly Bean will take care of this automatically.
Now the trickier part: Keeping the service running on its own thread. As many things in Android this seems harder than it needs to be (or maybe I'm lacking some information here). You can't use an IntentService, because that will shut down automatically the first time an AsyncTask takes over and let's the onHandleIntent callback complete.
You need to setup your own thread and event loop on the service:
public class AsyncService extends Service {
private static final String TAG = AsyncService.class.getSimpleName();
private class LooperThread extends Thread {
public Handler threadHandler = null;
public void run() {
Looper.prepare();
this.threadHandler = new Handler();
Looper.loop();
}
}
private LooperThread serviceThread = null;
private Handler serviceThreadHandler = null;
#Override
// This happens on the UI thread
public void onCreate() {
super.onCreate();
}
#Override
// This happens on the UI thread
public int onStartCommand(Intent intent, int flags, int startId) {
this.serviceThread = new LooperThread();
this.serviceThread.start();
while(this.serviceThread.threadHandler == null) {
Log.d(TAG, "Waiting for service thread to start...");
}
this.serviceThreadHandler = this.serviceThread.threadHandler;
this.serviceThreadHandler.post(new Runnable() {
#Override
public void run() {
doTheFirstThingOnTheServiceThread();
}
});
return Service.START_STICKY;
}
// doTheFirstThingOnTheServiceThread
}
No you need to make sure that each time an AsyncTask returns to the UI thread, you end up in your service thread instead:
// This happens on the serviceThread
private void doTheFirstThingOnTheServiceThread() {
// do some stuff
// here we can reuse a class that performs some work on an AsyncTask
ExistingClassWithAsyncOperation someUsefullObject = new ExistingClassWithAsyncOperation();
// the existing class performs some work on an AsyncTask and reports back via an observer interface
someUsefullObject.setOnOperationCompleteListener(new OnOperationCompleteListener() {
#Override
// This happens on the UI thread (due to an ``AsyncTask`` in someUsefullObject ending)
public void onOperationComplete() {
serviceThreadHandler.post(new Runnable() {
#Override
public void run() {
doTheSecondThingOnTheServiceThread();
}
});
}
}
someUsefulObject.performOperation();
}
// This happens on the serviceThread
private void doTheSecondThingOnTheServiceThread() {
// continue working on the serviceThread
}
So, this works for me. I'd be delighted to see a simpler solution for this. Note that the solution requires the service to know that is will be called back by the ExistingClassWithAsyncOperation on the UI thread. I don't particularly like this dependency, but don't know how to do better right now. However, I don't have to rewrite a lot of existing classes that perform asynchronous operations using AsyncTask.
I have a minor problem in one of my apps. It uses a BroadCastReceiver to detect when a call finishes and then performs some minor housekeeping tasks. These have to be delayed for a few seconds, to allow the user to see some data and to ensure that the call log has been updated. I'm currently using handler.postDelayed() for this purpose:
public class CallEndReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if (DebugFlags.LOG_OUTGOING)
Log.v("CallState changed "
+ intent.getStringExtra(TelephonyManager.EXTRA_STATE));
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE)
.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)) {
SharedPreferences prefs = Utils.getPreferences(context);
if (prefs.getBoolean("auto_cancel_notification", true)) {
if (DebugFlags.LOG_OUTGOING)
Log.v("Posting Handler to remove Notification ");
final Handler mHandler = new Handler();
final Runnable mCancelNotification = new Runnable() {
public void run() {
NotificationManager notificationMgr = (NotificationManager) context
.getSystemService(Service.NOTIFICATION_SERVICE);
notificationMgr.cancel(12443);
if (DebugFlags.LOG_OUTGOING)
Log.v("Removing Notification ");
}
};
mHandler.postDelayed(mCancelNotification, 4000);
}
final Handler updateHandler = new Handler();
final Runnable mUpdate = new Runnable() {
public void run() {
if (DebugFlags.LOG_OUTGOING)
Log.v("Starting updateService");
Intent newBackgroundService = new Intent(context,
CallLogUpdateService.class);
context.startService(newBackgroundService);
}
};
updateHandler.postDelayed(mUpdate, 5000);
if (DebugFlags.TRACE_OUTGOING)
Debug.stopMethodTracing();
try
{
// Stopping old Service
Intent backgroundService = new Intent(context,
NetworkCheckService.class);
context.stopService(backgroundService);
context.unregisterReceiver(this);
}
catch(Exception e)
{
Log.e("Fehler beim Entfernen des Receivers", e);
}
}
}
}
Now I have the problem, that this setup works about 90% of the time. In about 10% of cases, the notification isn't removed. I suspect, that the thread dies before the message queue processes the message/runnable.
I'm now thinking about alternatives to postDelayed() and one of my choices is obviously the AlarmManager. However, I'm not sure about the performance impact (or the resources it uses).
Maybe there is a better way to ensure that all messages have been processed before a thread dies or another way to delay the execution of those two bits of code.
Thank you
I'm currently using handler.postDelayed() for this purpose:
That's not a good idea, assuming the BroadcastReceiver is being triggered by a filter in the manifest.
Now I have the problem, that this setup works about 90% of the time. In about 10% of cases, the notification isn't removed. I suspect, that the thread dies before the message queue processes the message/runnable.
More accurately, the process is terminated, taking everything with it.
I'm now thinking about alternatives to postDelayed() and one of my choices is obviously the AlarmManager. However, I'm not sure about the performance impact (or the resources it uses).
It's not that bad. Another possibility is to do your delayed work in an IntentService -- triggered via a call to startService() -- and have it sleep on its background thread for a couple of seconds.
Let's try a new way of doing this. Using RxJava. It's much simpler to prototype and easier to manage lots of threads if you want to ever run hundreds of such delayed tasks concurrently, sequentially, coupled with async tasks, chained with synchronous chained async calls etc.
Firstly, set up the Subscriber. Remember new on Subscriber should be done only once to avoid memory leaks.
// Set up a subscriber once
private Subscuber<Long> delaySubscriber = new Subscuber<Long> () {
#Override
public void onCompleted() {
//Wrap up things as onCompleted is called once onNext() is over
}
#Override
public void onError(Throwable e) {
//Keep an eye open for this. If onCompleted is not called, it means onError has been called. Make sure to override this method
}
#Override
public void onNext(Long aLong) {
// aLong will be from 0 to 1000
// Yuor code logic goes here
// If you want to run this code just once, just add a counter and call onComplete when the counter runs the first time
}
}
The snippet below will just emit the 1 in the onNext() of the subscriber.
Note that this is done on the Computation Threadpool created and managed by the RxJava library.
//Now when you want to start running your piece of cade, define an Observable interval that'll emit every second
private Observable<Long> runThisAfterDelay = Observable.just(1).delay(1000, TimeUnit.MILLISECONDS, Schedulers.computation());
// Subscribe to begin the emissions.
runThisAfterDelay.subscribe(delaySubscriber);
If you want to run a code after every one second, say, then you can do this:
private Observable<Long> runThisOnInterval = Observable.interval(1000, TimeUnit.MILLISECONDS, Schedulers.computation());
In addition to the first answer, you might want to consider what the API documentation says for the onReceive method:
[...] The function is normally called within the main thread of its process, so you should never perform long-running operations in it [...]
So it looks like generally it is not a good idea to start something that waits a couple of time within onReceive (even though, in your case it's less than the 10s limit).
I had a similar timinig problem with the BroadcastReceiver. I couldn't get my results processed even though I onReceive had been called with exactly what I was exepcting. It seemed that the thread the BroadastReceiver was running in, got killed before my result processing could finish. My solutuion was to kick off a new thread to perform all processing.
AlarmManager seems not to work very well for short periods of time like 10 seconds and according to user reports the behaviour heavily depends on the firmware.
At the end I decided to use Handler and Runnable in my service.
When creating the Handler, be sure to create it inside the Service class, not inside the BroadcastReceiver since in the last case you'll get Can't create Handler inside thread that has not called Looper.prepare()
public class NLService extends NotificationListenerService {
private NLServiceReceiver nlservicereciver;
Handler delayUpdateHandler = new Handler();
private Runnable runBroadcastUpdate;
public void triggerViewUpdate() {
/* Accumulate view updates for faster, resource saving operation.
Delay the update by some milliseconds.
And if there was pending update, remove it and plan new update.
*/
if (runBroadcastUpdate != null) {
delayUpdateHandler.removeCallbacks(runBroadcastUpdate);
}
runBroadcastUpdate = new Runnable() {
public void run() {
// Do the work here; execution is delayed
}
};
delayUpdateHandler.postDelayed(runBroadcastUpdate, 300);
}
class NLServiceReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
triggerViewUpdate();
}
}
}