I am using the InstrumentationTestCase class in order to unit test some things within an activity.
I need to be able to check the SharedPreferences's contents and edit them, before this activity is launched.
I cannot use the setUp method to create the Activity and access it's SharedPreferences object to edit it, and then close that activity before finishing the setUp method because it apparently is locking the tests processing.
I also cannot access the SharedPreferences after I have launched the activity inside the test because as soon as the Activity is launched, it will already change the SharedPreferences object and act according to it, before I had the chance to get it's reference.
I apparently cannot access the SharedPreferences before either, because I have no Activity object... and as soon as I do, it is already executing code and being launched...
So, my question is, is there any way to access the SharedPreferences (and any other Activity information) of this Activity before I have the Activity actually created through an Intent?
I cannot change it to an ActivityInstrumentationTestCase2 because my test uses a second activity in it's process, so I can't just change to this class and use it's setUp() method to access the SharedPreferences.
I found the best simpler way to do this through the instrumentation only, without having to edit the application's architecture or any of the access attributes.
I achieved it through this:
Instrumentation instrumentation = getInstrumentation();
instrumentation.getTargetContext().getSharedPreferences(..);
This way I can access the SharedPreferences before any Activity is launched by the instrumentation.
Thanks for all the help, hints and other alternatives anyway.
Well... To tell you frankly.. I am not able to visualize your scenario. But is checking for info in application is doable ?
Create a class which extends android.app.Application and specify class name in Manifests child application element.
Sample Code:
import android.app.Application;
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
//try and access activity info here.
}
}
When your application is launched first class method to execture is onCreate of your application and has all the lifecyle events of that of any activity..
You must define extended application class in manifest by:
<application
android:name=".MyApplication"
android:label="#string/application_name">
I hope this ca give you some overview.
I haven't tried it, but if you set the mode to MODE_WORLD_READABLE and possibly MODE_WORLD_WRITEABLE instead of MODE_PRIVATE, I would think you could access the shared preferences from another application before the activity under test starts.
You could probably also use a different activity or service within the apk, or another apk that establishes a shared user ID and has the same certificate, to do the access without changing the access mode.
Related
I need to implement very specific code in the start of the application.
I mean, not in the start of the activity(onCreate() or onStart()) but in the start of the application.
I had one solution which is not good for me, which is to have a base activity called "MyBaseActivity" and then extends from it in all of my activities.
This solution is not good for me, because this solution makes me to be able to do only one specific thing in the onCreate of each activity(the specific code I talked about), which is not what I want.
I want every activity to be able to do different things according to their onCreate() func, and in addition to do the specific code that I talked about above.
Therefor, I need to access the start of the application, or that you have another solution for me.
Thank you !
The Application class, or your subclass of the Application class, is instantiated before any other class when the process for your application/package is created.
You need to extend application class.
public class AppApplication extends Application{
#Override
public void onCreate() {
super.onCreate();
//Do whatever you want
}
}
And this AppApplication class should be included in manifest file.
<application
android:allowBackup="true"
android:name=".AppApplication"
android:icon="#mipmap/ic_launcher"
I need to implement very specific code in the start of the application.
Every time when Android "gets a request" to start any of your app component (Activity, Service, BroadcastReceiver) and your app isn't running yet, it forks the app_process (a.k.a zygote), changes its name to your.package.name defined in AndroidManifest.xml, initializes an Application instance, calls its onCreate() method, then instantiates the component requested and calls its lifecycle methods (Activity's onCreate(), Service's onCreate() or BroadcastReceiver's onReceive()).
There can be only single instance of Application class which lives untill the app process dies. That said, any class instances you create within your extended Application class will also live until the app process is killed by the system.
Example: Understanding the Android Application Class
I have written an activity A, when users press a button, it will do MyConfig.doSomething() where MyConfig is simple class with activity A passed to it.
public class A extends PreferenceActivity {
private MyConfig mMyConfig;
/* pseudo code, when button clicked, call */
mMyConfig.doSomething();
}
In mMyConfig, it accesses SharedPreferences for some configuration. Thus, I can do this to pass the activity to mMyConfig for calling getSharedPreferences().
mMyConfig = new MyConfig ( this );
Here comes my request:
I want to do something that MyConfig.doSomething() already does, but except when users click some button to invoke it, I want to invoke it when Android Boots-Up.
I can write another class to extend BroadcastReceiver and then starts activity A by calling startActivity(A.class), and then in A, do some tricks to make mMyConfig.doSomething() happen. It works but the Application will be shown on screen when Android Boots-Up.
I want to make mMyConfig.doSomething() happen implicitly without letting users be aware of it. I suppose two possible solutions but I don't know how to do it.
Solution A:
Write a class that extends BroadcastReceiver, start a service (instead of activity A) that reads the SharedPreferences of A and create MyConfig object to do doSomething(). However, I don't if this can work if activity itself is never launched and how could I do this (read SharedPreferences from a service)?
Solution B:
Write a class that extends BroadcastReceiver, start activity A without showing it, put it to activity stack by calling startActivity(A.class) in onReceive. Is this possible?
Instead of Activity, which are meant to be visible to the user, you can make your BoardcastReceiver to start a Service instead. It is meant to perform tasks in the background without disturbing the user. The official guide is a nice place to start with.
Edited:
To access the SharedPreference of your application, simply call this line inside your service:
SharedPreferences pref = PreferenceManager.getSharedPreferences();
can I use activiy one time(register activity) and switch the main launcher after using to different activity?
another question if I may,
If I create parameter x in one of the activities in my application, can I use this parameter in other activities?...If yes, how I can do that?
thanks :)
You cannot dynamically change the launcher activity once it has to be only 1 activity that is defined in the manifest file.
I would recommend having something like a landing or splash activity which checks a shared preference variable, to decide which activity to launch, for example either a login activity or another activity.
You should not access a variable in an activty from another activity, you should store these in data holding classes. however if you want to do it, for a good reason, simply make it static.
You cannot adjust the manifest after running your application. What you can do is have your default launcher activity write to SharedPreferences once it has been run once. Inside of that activity check to see if that preference has been set and if it has just finish that activity and launch your new activity, the user will not see anything if you do this in the onCreate of the launcher activity.
As for passing params between activities you should use intent extras. For example to pass a string use putExtra(String key, String value), and to get that parameter inside of the new activity use getStringExtra("Key").
For global variables accessable from different activities you can also extend Application class and then access it via getApplicationContext().
1. One time activity launch
You can't change the main launcher. It's a static information. What you could do is following:
// in the beginning of onCreate
// first launch could be loaded from shared preferences
// see 2. for more
if (!firstLaunch) {
// start another activity
finish();
return;
}
2. Use data in another activity
One way is to persist the data and load it somewhere else. You will find all information you need in the Data Storage article.
If your data is primitive you could try to pass it by intent to another activity. See Using integer from one class in another Android.
If it is complex you could try to implement an own Application class and use helper methods to access global data. See Android: Accessing resources without an Activity or Context reference.
Be careful with that, please read the Avoiding Memory Leaks article then.
I am writing an android test case which requires the execution of a seperate Activity to the Activity being tested (not for the sake of testing but just to gain access to the contentresolver so I can change some telephony settings).
Is it at all possible to start an activity from a test case or in another manner.
I am aware of the AndroidTestCase class used to test activities, an I am using it in my tests, however I need to use a ContentResolver to change telephony settings and then test the reaction of the activity under test so I need another application component to change these settings.
Note: I release the complexity behind multiple activity testing (requiring an ActivityManager) but I only want to use it's method to alter the settings so I could even have the logic in the onCreate method.
Android provides a special instrumentation framework for testing Activities. You must use this framework since Activities have a complex lifecycle that is un-invokable outside this provided framework. Look under the Testing link in the Developmentsection of the Android documentation for Activity Testing. If this doesn't answer your question, you might rephrase it a bit.
Edit
You should really be extending ActivityUnitTestCase to test an Activity, not AndroidTestCase. You get more functionality specific to what you need to test. If you extend ActivityUnitTestCase there is a function called launchActivity. It'll launch the activity you need and give you an instance of the activity so that you can call methods on it such as set, get, and finish. This should do anything you need for manipulating single and multiple activities at a time.
Example code:
#MediumTest
public class Test extends ActivityUniTestCase<HelloActivity> {
public Test(Class<HelloActivity> activityClass) {
super(activityClass);
}
#MediumTest
public void testLifeCycleCreate() {
HelloActivity hActivity = startActivity(new Intent(Intent.ACTION_MAIN), null, null);
getInstrumentation().callActivityOnStart(hActivity);
getInstrumentation().callActivityOnResume(hActivity);
GoodByeActivity gActivity = launchActivity("package.goodbye", GoodByeActivity.class, null);
gActivity.finish();
}
}
AndroidTestCase and ActivityInstrumentationTestCase2 both provide methods to get Context
AndroidTestCase:
getContext();
ActivityInstrumentationTestCase2
getInstrumentation().getContext();
You can use these contexts to launch another activity, however the permissions is adopted from the application under test, so in my case with the contentresolver I only have the same permission to alter settings I do in the application under test.
In my case this is no good so I had to create a seperate application with it's own permissions and a background service I was then able to control by launching intents using the context.
I have a class in my Android application that sub-classes the AndroidApplication object. The documents say:
public void onCreate ()
Since: API Level 1 Called when the
application is starting, before any
other application objects have been
created. Implementations should be as
quick as possible (for example using
lazy initialization of state) since
the time spent in this function
directly impacts the performance of
starting the first activity, service,
or receiver in a process. If you
override this method, be sure to
call super.onCreate().
I placed a breakpoint on my sub-class's constructor and when I run my application, it is never reached. Naturally, when I call the sub-class's getInstance() method from other code it returns NULL since the instance variable is (supposed to be) initialized when the constructor is called.
Can anyone tell me what is wrong? I would assume from the docs that I don't have to create an instance of the AndroidApplication sub-class myself, or do I? Am I supposed to modify my manifest file somehow to add the AndroidApplication sub-class and if so, how?
-- roschler
I'm posting the answer here for others. Yes you need to add the name of your Application object sub-class's name to the Android manifest. For Eclipse users, the easiest way to do this is to open the AndroidManifest.xml file, select the Application tab in the manifest editor, and use the Browse button next to the Name field to find your Android Application object sub-class name and select it. The manifest file will be updated properly to register it. I just did that and it worked.
I had a problem of not having a . before my application class name.
Should be:
android:name=".MyApp"
since the MyApp class is in the package defined in the manifest.