I'm doing some black box testing (using UiAutomator 2.0 btw, extending InstrumentationTestCase) and I need to know:
1 - when a new activity is created
2 - to know if it's the first time the activity is created
I need this because there are some tests that I want to apply when a new activity appears but I want this detection to be automatic, not manual.
Prior to Android L there was the UiDevice.getCurrentActivityName() method. However, now it is deprecated (moreover, they don't even ensure it works for previous versions). This also happened with the options to getting the activity though the PackageManager.
As such, I would like to know:
Is it possible to programatically detect a new activity? If so, is is possible to know if it's the first time the activity occurs.
If it's not possible, how should I define an activity according to its UI? How many widgets should change for me to conclude it's a different activity?
Thanks.
EDIT: Just to be clear, I don't want to test what happens when the activity is created, I want to be able to identify if it's the first time this activity occurs in a run.
Here is what I currently implemented for this problem, base on a assumption that the same Activity won't change it's UI View hierarchy dynamically. This is OK to me, seems I only want to distinguish between UI changes, not necessary for Activities.
1.Build a signature to identify between screens
signature1:FrameLayout;ListView;LinearLayout;RelativeLayout;...
signature2:FrameLayout;FrameLayout;FrameLayout;LinearLayout;...
2.Then, use a List to keep screens you already known.
3.For performance, you can use a fixed length for screen signatue.
The idea is refer to this paper
And if adb is ok to you, you can use this command,
adb shell dumpsys activity
This refer to another post here
Related
in my application (minSdkVersion 17, but I am flexible concerning this), I have a single activity. It displays some kind of timetable. I want to let it show the current day and scroll to the correct time.
This functionality is already working perfectly fine.
I want to do this everytime when the app is started, or everytime when the app becomes active again (e.g. after pressing the home button and just clicking the app icon again without killing the app inbetween).
But I do NOT want to do this, when the device is rotated.
For example, I have a method:
private void scrollToNow() {
// do the calculation and scroll all views to the correct position
// this is code I already have fully functional!
}
And I want to execute it every time the activity gets active again, but NOT on orientation change.
I tried a lot of combinations (in onStart, onResume, onCreate), but none of them did the trick. I tried to build a solution using the savedInstanceState but failed.
Anybody got some tips or useful links for me?
Thanks alot,
Oliver
Please, think twice before you decide to check configuration changes manually.
If your application doesn't need to update resources during a specific configuration change and you have a performance limitation that requires you to avoid the activity restart, then you can declare that your activity handles the configuration change itself, which prevents the system from restarting your activity.
Note: Handling the configuration change yourself can make it much more difficult to use alternative resources, because the system does not automatically apply them for you. This technique should be considered a last resort when you must avoid restarts due to a configuration change and is not recommended for most applications.
Try to save some flag in onSaveInstanceState and in onCreate check if there is savedInstanceState, then save it as field for example. This will give you information about does activity is 'recreated' or not. Then in 'onResume' check is this flag set or not. If not, then you are not 'recreated' your activity, so you can invoke scrollToNow()
I dont want to recreate layout when screen orientation change
Did you tried to add this line to your AndroidManifest.xml android:configChanges="screenLayout|screenSize|orientation" like that :
<activity
android:name="youractivity"
android:configChanges="screenLayout|screenSize|orientation"
android:label="#string/title_activity_create_note"
android:theme="#style/AppTheme"
android:windowSoftInputMode="stateAlwaysHidden" />
For more information you can take a look at : manifest/activity-element in that page go to android:configChanges section and read please .
When adding this you must handle onConfigurationChanged() method by yourself instead of Android System.
Please read carefully Note section in that page :
Note: Using this attribute should be avoided and used only as a last resort. Please read Handling Runtime Changes for more information about how to properly handle a restart due to a configuration change.
Also i am using this in my application maybe you can try this too : android:screenOrientation="nosensor" in that page you can find information about it too.
I'm simply trying to change between xml files/layouts.
In my main activity I have startActivityForResult(new Intent(this,playlist.class), 0);
I've added the class to my manifest, created the class where the package is com.site.mainactivity, and superclass is android.app.Activity.
I didn't "extends playlist" in my main activity
My logcat only shows "showStatusIcon on inactive InputConnection", "InputConnection = android.view.imputmethod.BaseInputConnection#40532b90, active client = false"
When I try to start the new activity/switch layout, my home screen shows, but my app is still running in the background. When I go back to it, the app takes me back to the main screen.
What am I doing wrong?
Thanks
This sounds like a problem with how the Activity stack is being maintained. Specifically this is because based on the Manifest properties, an Activity can have different properties that specify how the Activity should be treated by the manifest ie. if it is included in the Activity stack or not and/or Also this could include where the main entrance of the application is, and whether or not an external intent can go to a specific screen in the application.
With manipulation of this it is easy to control. Look up the ActivityManager and how tasks are retrieved and maintained and analyze the design flow of your application. You must fully understand how you want it to work to fully solve your problem. A flow chart would aid you in this diagnosis.
Learn to control your flow properly.
If you just want to change the layout, you can either:
call setContentView again
use singleTop and launch the same activity but with a different layout
close the first Activity with finish() after launching the second
What I did to bypass this hurdle was simply use getLayoutInflater().inflate(R.layout.main, null); as a View and then setContentView(v)
I just need to reinitialize events, views, etc so that the program runs as it did before it changed the view.
(Note that I've searched online for the warnings I'm describing below, and have come up with next to nothing about them.)
I'm working with API level 10. I have a preference screen (XML-based), and one of the options in there creates a custom ListActivity as follows:
PreferenceActivity contains an option that creates a...
ListActivity which is a dialog that employs...
setOnClickListener() which contains an onClick() method that (right before calling finish()) will startActivity() a new Intent...
sub-Activity which starts up an...
AsyncTask which does variable time work which when done calls...
onPostExecute() which calls finish()
The thing is, it works... but I'm getting a raft of warning starting with:
10-16 21:59:25.010: WARN/WindowManager(170): Rebuild removed 4 windows but added 3
10-16 21:59:25.010: WARN/WindowManager(170): This window was lost:.....
Curiously, this raft of warnings ONLY comes up when the task executes quickly! When I added a Thread.sleep() call to my AsyncTask to artificially inflate its runtime it worked and threw no warnings whatsoever. In fact, as long as it takes more than (roughly) 500 ms to run it works fine. (Note that I tried using startActivityForResult() to no greater effect - the same problem occurs.)
The goal is that the user selects a preference item, they change its setting, some processing takes place, and then the user is left back at the preference menu they started on.
I'm betting it's a race condition... the order in which the windows are destroyed varies depending on that run-time... and I get the impression that when the sub-Activity closes before its parent ListActivity the warnings get thrown. But sprinkling a 1s sleep() in isn't a reasonable solution unless this is some sort of Android bug (unlikely, but then again I've reproduced a couple of those today already).
So, what's the flaw in this my that leads to this stream of warnings? It'd be nice to say "on preference, do this, then do that, then finish" but I think what I'm doing is the equivalent. Maybe not... thoughts?
Edit: I decided to try doing this ListActivity as a custom Dialog... that was one of the more painful things I've tried to do lately (getApplication() doesn't work and lots of other things seem to go wrong... it may be inexperience to some extent, but dialogs really weren't meant for this either...
Try the following two things:
Dismiss your dialog before calling finish() on its parent activity (PreferenceActivity).
Make sure you are starting your AsyncTask later in the sub-activity's lifecycle. I'm specifically thinking you should launch it in onResume().
My best guess is that the AsyncTask is calling finish() on the sub-activity, before the sub-activity has had a chance to fully start up. Why that would matter? I'm not sure. Something to try though. Good luck!
I have three simultaneous instances of an AsyncTask for download three files. When two particular ones finish, at the end of onPostExecute() I check a flag set by each, and if both are true, I call startActivity() for the next Activity.
I am currently seeing the activity called twice, or something that resembles this type of behavior. Since the screen does that 'swipe left' kind of transition to the next activity, it sometimes does it twice (and when I hit back, it goes back to the same activity). It's obvious two versions of the activity that SHOULD only get called once are being put on the Activity stack.
Could this be from both onPostExecute()s executing simultaneously and both checking the flags each other set at the exact same time? This seems extremely unlikely since two processes would have to be running line-by-line in parallel...
*****EDIT*** A lot removed from this question since I was way off in what I thought was wrong. Nonetheless I found the answer here quite useful, so I have edited the question to reflect the useful parts.
The only way I can find that this is
possible is if both AsyncTasks'
onPostExecute() executed SO
simultaneously that they were
virtually running the same lines at
the same time, since I set the
'itemXdownloaded' flag to true right
before I check for both and call
startActivity().
Since they are both called on the main application thread, that's not possible, unless you're doing something really strange.
I would introduce some Log calls to ensure that you are not misreading the symptoms.
Beyond that, it is difficult to see any problems from your pseudocode, unless there's a possibility of other downloadID values beyond the three shown. For example, if there is a DL4, and DL4 completed after DL1 and DL2, DL4 would trigger your activity.
I know Android's Activity model is a bit different from what I usually consider to be an "app".
I want to do something (in this case, check some notifications on a server and show them if available) when my app is "launched". What is a good way to accomplish this?
I likely don't want to do it in an activity's OnCreate, since each activity can be created any number of times - the code would get called more often than necessary.
The app also has multiple entry points - would I have to duplicate the check in each activity?
What I'm thinking of doing is setting up this code inside the Application object, along with a flag that tracks whether it's already been called - and just call it from each Activity's onCreate().
Is there a better or more "proper" way to do this?
The right, Android-approved way to do this is:
Create your own android.app.Application class
Override the onCreate method
In the AndroidManifest.xml, change the android:name attribute of the application element to the name of your class
Now, whenever your app is "started" (any one of your activites is started for the first time and no other instances are alive) onCreate will be called.
You may also find the onTerminate method useful.
Can you just check if the bundle passed to onCreate() is null?
It's not null "If the activity is being re-initialized after previously being shut down..."
There's probably no harm in putting it in onCreate; the Activity is really only destroyed when the OS needs the RAM for something else, not when the user goes to another app.
EDIT: You can also have a Service that runs when the device gets booted up, too. This might be a better option if you also want to check when the app starts, since you'll only have to call context.startService from the Activity to run the check. Just be sure to stop it when it's done if you don't need it to be persistent.