In my application rather than following the regular hierarchy of the ActiveAndorid,
I'm explicitly calling with the .initialize() method by passing the getApplicationContext.
However, the TableInfo returned doesnt have any Tables from the model class that I'm creating.
I tried debug their code and it seems an issue with the classloader they are using.
My code is:
ActiveAndroid.initialize(getApplicationContext());
TestModel model=new TestModel();
model.value="hello";
model.save();
You should not use getApplicationContext. It might not return the context of your application. The naming of getApplicationContext is misleading.
More info here: getApplication() vs. getApplicationContext()
Related
This question already has answers here:
Non-static variable cannot be referenced from a static context
(15 answers)
Closed 3 years ago.
Here is my method:
public Cursor rawQuery(String sql, String[] selectionArgs) {
try {
return m_db.rawQuery(sql, selectionArgs);
} catch (SQLiteException e) {
reportException(Context.getApplicationContext(), e);
return null;
}
}
Android Studio (3.5.3) complains saying
Non-static method getApplicationContext() cannot be referenced from a static context.
I don't see any static context here. rawQuery is a perfectly good class method of a class which is a wrapper around SQLiteDatabase to save me having to check for exceptions on every call. The exception checks are needed because it's accessing a public database and some other process may have modified it in such a way that my operation fails (for example by dropping one of my tables). It is (currently) only created and its methods called from an Activity. Of course I could pass the calling activity's context, but this is clumsy since it isn't needed most of the time and IMHO it's very poor programming style to include extra arguments in the methods of a wrapper class.
reportException does what its name says and writes a log file or displays a Notification or a Toast, depending on circumstances, and all of these need a context.
I've seen suggestions on the net to create a static instance of a subclass of Application to cache the application context. As commenters have pointed out, this doesn't always work if you need the application context in a class constructor (or anything which is called from one), but I don't expect to do this. My wrapper class is created as needed when I want to access the database. However I'm not sure if tha Application subclassing trick works if I open a database in a background server which may get kicked out of memory when not active and later restarted by the OS. It may be that the only solution is to cache the creator's context in the constructor of the wrapper class: this only requires passing the context once. However I don't much like the idea of keeping a copy of the passed context: it looks inelegant and a potential problem with garbage collection since I have to take care not to use the cached context when creating anything persistent..
However I still don't see Android Studio's justification for complaining in the case shown. I tried removing all the calls to rawQuery and it still complains, so it isn't walking the call tree to look for a non-static context. It looks as if it may be complaining if getApplicationContext is used in any class which isn't a subclass of Activity, which certainly isn't justified.
I don't see any static context here.
The "static context" referred to by the error message is the way you are calling the method: Context.getApplicationContext(). Since you are using the Context class name, this counts as a "static context". You need a Context instance in order to call getApplicationContext().
Of course I could pass the calling activity's context, but this is clumsy since it isn't needed most of the time and IMHO it's very poor programming style to include extra arguments in the methods of a wrapper class.
Yes, I agree that you should keep your argument list as trimmed down as possible. You say that this method is a wrapper around SQLiteOpenHelper which requires a Context as one of its constructor parameters. So presumably your own constructor takes a Context to pass to the wrapped SQLiteOpenHelper instance. One solution is to keep that Context as a field in your class. Then you can just use this.context.
I have a ViewModel in which there is a method which has the following line of code:
billDate.set(!TextUtils.isEmpty(SampleApp.getInstance().getAccountManager().getDueDate()) ?
String.format(SampleApp.getInstance().getApplicationContext().getString(R.string.due),
SampleApp.getInstance().getAccountManager().getBillingDueDate()) :
SampleApp.getInstance().getApplicationContext().getString(R.string.missing_due_date));
I have a test class using Mockito to test the different methods in ViewModel. But it is failing with NullPointerException at this line:
String.format(SampleApp.getInstance().getApplicationContext().getString(R.string.due),
Below is the log:
java.lang.NullPointerException
at java.util.regex.Matcher.getTextLength(Matcher.java:1283)
at java.util.regex.Matcher.reset(Matcher.java:309)
at java.util.regex.Matcher.<init>(Matcher.java:229)
at java.util.regex.Pattern.matcher(Pattern.java:1093)
at java.util.Formatter.parse(Formatter.java:2547)
at java.util.Formatter.format(Formatter.java:2501)
at java.util.Formatter.format(Formatter.java:2455)
at java.lang.String.format(String.java:2940)
While running a test case, I see the log showing some error related to Pattern
Can somebody suggest, how to test the String.format() method?
First of all, you should not be importing android view packages into your ViewModel. So skip using things like TextUtils inside ViewModels.
As to the getApplicationContext().getString(), create an interface for this. Something like:
interface StringProvider {
String getString(int resource);
}
Then pass that interface in your ViewModel constructor and use that to get the string you want.
When you initialize the ViewModel, you can pass a concrete implementation of StringProvider like this:
class StringProviderImpl implements StringProvider {
String getString(int resource) {
return SampleApp.getInstance().getApplicationContext().getString(resource);
}
}
This way, for your unit tests, you can just mock StringProvider and don't have to worry about dealing with contexts inside your ViewModel and the related test code.
You don't need to test the String.format method. That is not your code, and your goal should be to test your own code. But your code is using that method, so you need to test your code. This is the part you are trying to validate or mock out as I understand it:
String.format(SampleApp.getInstance().getApplicationContext().getString(R.string.due), SampleApp.getInstance().getAccountManager().getBillingDueDate())
which makes several calls to SampleApp to get an instance. Since those calls to SampleApp.getInstance are static method calls, you won't be able to mock them out. There isn't enough code posted to know what SampleApp is or what SampleApp.getInstance() returns or to know if any of the subsequent calls on that instance are returning null, but one of them is. So I think to solve this you need to look at the what the getInstance method returns. If you can't touch that code and you're hoping to only modify your test classes, you may not be able to test this with mockito due to the static method.
But otherwise you will need to build a way for your tests so the call to SampleApp.getInstance returns a mock object as the instance instead of whatever real instance I presume it is returning now. Then you can mock out the subsequent methods like getApplicationContext and getString to make them return canned responses so that the string.format call will not fail on a null input.
One note of caution--if you do end up making the static getInstance method return a mock, but sure you have proper cleanup when your test is done to set it back to what it was returning originally so you don't inadvertently modify something that might cause another unrelated unit test to fail. That is always a risk if you change something returned by a static method in a unit test since you are effectively changing it for all tests.
Considering that the test fails after the AccountManager was already used, you should have set up the SampleApp as a mock or fake already.
SampleApp app = SampleApp.getInstance()
AccountManager am = app.getAccountManager();
Context context = app.getApplicationContext();
billDate.set(!TextUtils.isEmpty(am.getDueDate()) ?
String.format(context.getString(R.string.due), am.getBillingDueDate()) :
context.getString(R.string.missing_due_date);
Now you only need to make sure to mock the Context you provide with with app.getApplicationContext() or the SampleApp itself, if you use app.getString() directly.
doReturn(dueFormatString).when(context).getString(R.string.due);
doReturn(dueMissingString).when(context).getString(R.string.missing_due_date);
But in general you should abstract the Context away. Not using it will simplify your code and therefore your testing a lot.
Also consider using context.getString() instead of String.format() for formatting a string you load from a resource. It's as easy as adding the format arguments as parameters to the call.
context.getString(R.string.due, am.getBillingDueDate())
while casting objects in java this rule must apply
Instances of classes can also be cast to instances of other classes,
with one restriction: The class of the object you're casting and the
class you're casting it to must be related by inheritance; that is,
you can cast an object only to an instance of its class's sub- or
super class-not to any random class.
I don't understand how this casting will work since i have not seen any relationship through inheritance in the android documentation:
TelephonyManager manager = (TelephonyManager) getBaseContext()
.getSystemService(Context.TELEPHONY_SERVICE);
the above is casting a context object to a TelephonyManager ?
In your code snippet, the casting is applied to the return value of getSystemService(), not a Context object. The getSystemService() method's signature indicates only that it shall return an Object. And the documentation indicates that the exact class (a subclass of the Object class -- duh) depends on the argument to the method.
The method getSystemService() in Context returns an Object. Since every single reference type in Java extends Object, it's allowed to attempt to cast it to anything.
Keep in mind that you're not casting a Context instance, but the result of getSystemService.
It's not casting Context, it's casting the return value of Context.getSystemService(String), which is declared to return Object. The actual return type obviously has an inheritance relationship with Object, no matter what it is. But if it doesn't have an inheritance relationship with TelephonyManager, the cast will fail at run time.
This part of the Android API is very badly designed. They could easily have improved the type safety and avoided the ugly casting by providing methods like Context#getTelephonyManager(). For that matter, they still could.
Disclaimer: this is my first ever Android test project with Robotium.
I'm facing a catch-22 situation with ActiveAndroid and Robotium. Here's my setup:
I want to test an activity that expects a long array extra. This array contains DB ids of ActiveAndroid objects.
To get the ActiveAndroid objects ids', I need to initialize ActiveAndroid first, calling ActiveAndroid.initialize(this.getActivity()) from my ActivityInstrumentationTestCase2 class.
The call to getActivity() fails since I didn't pass the long array extra. I can't create the long array extra because I haven't initialized ActiveAndroid, hence the catch-22.
Is there another way I can get a context in a test class? An application-wide context perhaps?
I found the solution:
ActiveAndroid.initialize(this.getInstrumentation().getTargetContext());
That way you can get the target's context before initializing the activity.
Is their any way to make singleton object by using xml.As we know if we write className with package it call the constructor of the class but i want to use this xml in various other xml files using include tag.But it call all the time its consturctor and creating various object of that.
<jp.ne.biglobe.common.CustomSlidingDrawer>
something
</jp.ne.biglobe.common.CustomSlidingDrawer>
it call the constructor of the CustomSlidingDrawer class As i included it several other file.
Please Suggest me how to make it singleton object.
Maybe you could create a normal class, not singleton that you instanciate through xml. All instances would have a static method getView that returns the singleton.
But this would be awfull design. Just a syntactic workaround.
Regards,
Stéphane