Default Shared Preferences : Source not found - android

I use Default Shared Preferences to save some data in them.
I have created a class to handle all this :
public class PreferencesHandler {
private Context mContext;
public PreferencesHandler (Context context) {
this.mContext = context;
}
public void setBoolean(String name, boolean value) {
PreferenceManager.getDefaultSharedPreferences(mContext).edit()
.putBoolean(name, value).commit();
}
public void setInt(String name, int value) {
PreferenceManager.getDefaultSharedPreferences(mContext).edit()
.putInt(name, value).commit();
}
public boolean getBoolean(String name, boolean defaultValue) {
return PreferenceManager.getDefaultSharedPreferences(mContext)
.getBoolean(name, defaultValue);
}
public int getInt(String name, int defaultValue) {
return PreferenceManager.getDefaultSharedPreferences(mContext).getInt(
name, defaultValue);
}
}
How you see I created a Handler class for easier access.
Also I have a Methods class where all my methods are stored.
And in that class I have a method which uses this handler class :
public class Methods {
private Context mContext;
public Methods(Context context) {
this.mContext = context;
}
public void process (PreferencesHandler pref, String prefName, int default) {
int mInt= pref.getInt(prefName, default);
//The rest doesn't matters
}
}
I call this method in my activity class.
With the debugger I found out that the error is in the Handler, when it executes the return line, it opens the PreferenceManager.class with the text "Source not found".
It says that the JAR file android.jar has no source attachment.
What should I do to fix this?

The problem is probably that the Activity that you use to call the constructor of PreferencesHandler gets destroyed, and then you try to use that PreferencesHandler in a new instance of that activity.
If this is the problem then this change in both constructors should fix that:
mContext = context.getApplicationContext();
As for the source code of PreferenceManager.class: use the Android SDK manager to install the Android sources and restart your IDE.
In Eclipse the Android SDK Manager can be found here: Window -> Android SDK Manager

Related

Mock PreferenceManager with Mockito

I am new in Android unit testing and I want to add some unit tests in an existing project. I am using the MVP design architecture. Inside my presenter, I have a call to PreferenceManager in order to get the default SharedPrefences but it always returns null. I have followed some tutorials and advices across stackoverflow on how to mock PreferenceManager and SharedPreferences but I can't make it work. This is my presenter class
#RunWith(MockitoJUnitRunner.class)
public class SettingsPresenterTest {
#Mock
private SettingsView mView;
#Mock
private LocalConfiguration conf;
private SettingsPresenter mPresenter;
public SettingsPresenterTest() {
super();
}
#Before
public void startUp() throws Exception {
MockitoAnnotations.initMocks(LocalConfiguration.class);
MockitoAnnotations.initMocks(PreferenceManager.class);
mPresenter = new SettingsPresenter(mView);
final SharedPreferences sharedPrefs =
Mockito.mock(SharedPreferences.class);
final Context context = Mockito.mock(Context.class);
Mockito.when(PreferenceManager.getDefaultSharedPreferences(context)).
thenReturn(sharedPrefs);
}
#Test
public void notificationsEnabledClicked() throws Exception {
boolean notifsEnabled = false;
mPresenter.notificationsEnabledClicked(notifsEnabled);
Mockito.verify(mView).setNotificationsView(notifsEnabled);
}
}
and here is the method where the SharedPreferences are returned null
public class LocalConfiguration {
public TerritoryDto getLastSavedTerritory() {
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(H.getContext());
String terrritoryString = preferences.getString(SAVED_TERRITORY,
null);
return
SerializerHelper.getInstance().deserialize(terrritoryString,
TerritoryDto.class);
}
}
Could you give me some guidelines on how to resolve this error?
Instead of directly referring to Android SDK, abstract that out from your presenter logics. What this means is, that instead of performing PreferenceManager.getDefaultSharedPreferences(), create an abstraction and ask for territoryString from your abstraction.
What will this give to you, is that your presenter won't know about the precense of neither PreferenceManager nor SharedPreferences, which are from Android SDK, thus you would have enough seams to perform pure unit testing.
Having said this, let's implement the abstractions. Having declared following interface:
public interface Storage {
#Nullable
String getSavedTerritory();
}
To which the concrete implementation would be:
public SharedPrefsStorage implements Storage {
private final SharedPreferences prefs;
public SharedPrefsStorage(Context context) {
prefs = PreferenceManager.getDefaultSharedPreferences();
}
#Nullable
#Override
public String getSavedTerritory() {
return prefs.getString(SAVED_TERRITORY, null);
}
}
Then your presenter would become something like this:
public class LocalConfiguration {
final Storage storage;
public LocalConfiguration(Storage storage) {
this.storage = storage;
}
public TerritoryDto getLastSavedTerritory() {
final String territory = storage.getSavedTerritory();
return SerializerHelper.getInstance().deserialize(territory, TerritoryDto.class);
}
}
This would give you a seam to perform pure unit testing:
#Test
void someTest() {
when(storage.getSavedTerritory()).thenReturn("New York");
...
}
No need to worry about mocking PreferenceManager anymore.

Toast resource not found Resources$NotFoundException: File res/layout/transient_notification.xml

this problem is not always there, I can't find the cause of the problem, ask for help, thank you.
My code is
private static Toast systemToast;
public static Toast getSystemToast(Object resId) {
if (null == systemToast) {
// Apps is the Application.java
systemToast = Toast.makeText(Apps.getAppContext(), R.string.me_empty,
Toast.LENGTH_SHORT);
}
String res = String.valueOf(resId);
if (resId.getClass() == Integer.class) {
systemToast.setText(Integer.valueOf(res));
} else if (resId.getClass() == String.class) {
systemToast.setText(res);
}
systemToast.setDuration(Toast.LENGTH_SHORT);
return systemToast;
}
/** Apps.java **/
public class Apps extends Application {
private static Apps sContext;
#Override
protected void attachBaseContext(Context base) {
sContext = this;
}
public static Apps getAppContext() {
return sContext;
}
In some Android equipment, Error occurred, The error Log is:
android.content.res.Resources$NotFoundException: File res/layout
/transient_notification.xml from xml type layout resource ID #0x10900ef at
android.content.res.Resources.loadXmlResourceParser(Resources.java:2720) at
android.content.res.Resources.loadXmlResourceParser(Resources.java:2675) at
android.content.res.Resources.getLayout(Resources.java:1096) at
android.view.LayoutInflater.inflate(LayoutInflater.java:422) at
android.view.LayoutInflater.inflate(LayoutInflater.java:368) at
android.widget.Toast.makeText(Toast.java:282)
This error might be occurred, when pass context object not proper initialize or might be its referencing to null.
1.if you are using Fragment than, you can find Context in onAttach Method. And pass your getSystemToast Method.
**#Override
public void onAttach(Context context) {
super.onAttach(context);
}**
2. If you are using Activity, than get Context using getBaseContext() Method or ActivityName.this both will return you context
You no need to defined function for get Context. Android provide Following Method for get Context.
1.getApplicationContext() Application context is associated with the Applicaition and will always be the same throughout the life cycle.
2.getBaseContext()
3.onAttach() in Fragment.

Custom Class extends Application for Singleton Purposes

I tried to create custom class to fetch some values from SharedPreferences.
My aim is to reach to that values from any class.
I am getting null Pointer exception on
SharedPreferences prefs = getApplicationContext().getSharedPreferences("UserFile", MODE_PRIVATE);
My code is as below;
public class UserInfo extends Application {
private String token;
private String SAVED_USERNAME;
public UserInfo() {
SharedPreferences prefs = getApplicationContext().getSharedPreferences("UserFile", MODE_PRIVATE);
token = prefs.getString("Token", null);
}
public String getToken() {
return token;
}
}
What might be the wrong?
Usually Android components are initialized during their lifecycle. In this particular case you can't access application Context and SharedPreferences because they're not initialized yet.
Second problem might be (thanks to my crystall ball) that you did not added your Application to AndroidManifest
So, your first thought might be to move initialization code from constructor to onCreate. This would solve this particular problem.
However, it's a bad practice to do what you're doing. Because there can be only 1 Application component per application. This will limit you to 1 such singleton per app. Consider using Application to provide application Context as singleton and create another singleton for providing UserInfo.
No examples, please exercise yourself.
Just have this method in a util class. No need to extend application.
public static String getToken(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getString("Token", null);
}
There is a rule in android - don't use constructor of app component: Activity/Fragment/Application/Service... there is onCreate() method, because in your constructor context will be null. So move your code to onCreate(). Also you need set your UserInfo as application in Manifest.
You don't create constructor of Application class instead, use the code in onCreate():
#Override
public void onCreate() {
super.onCreate();
SharedPreferences prefs = getApplicationContext().getSharedPreferences("UserFile", MODE_PRIVATE);
token = prefs.getString("Token", null);
}
and use it from any activity:
UserInfo userInfo = (UserInfo)getApplication();
String token = userInfo.getToken();
public class MyApp extends Application {
private static MyApp _instance;
#Override
public void onCreate() {
super.onCreate();
_instance = this;
}
public static MyApp getInstance(){
return _instance;
}
public String getToken() {
return getSharedPreferences("UserFile", MODE_PRIVATE).getString("Token", null);
}
}
In your manifest:
<application
android:name="your.package.MyApp"
>
If you whant use :
String token = MyApp.getInstance().getToken();
Make sure you have registered this class in your AndroidManifest.XML file.
<application android:name=".UserInfo"
...
/>
Note: Your way for accessing shared preferences does not seem good. I rather myself declare a class named PreferencesHelper and put all preferences stuff there.
public class PreferencesHelper{
private SharedPreferences mPrefs;
public PreferencesHelper(Context context){
this.mPrefs = context.getSharedPreferences("name", Context.MODE_PRIVATE);
}
public getToken() {
return mPrefs.getString("Token", null);
}
public String setToken(String token) {
mPrefs.edit().putString("Token", token).apply();
}
}

Access application context in a storage class in Android

I have an app on Android 4.0. It uses the PreferenceManager class to -- among other things -- let the user specify how many decimal places of a number to show.
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
Generally I have no problem getting the app context in order to access the Preference Manager. My problem is that I have a class (let's call it Record) that isn't subclassing anything that has the app context; it's just a storage class, but it does have a field "NumDecPlaces". Right now, when I instantiate the class from within my app I just pass in the user's #dec places preference. It would be nice if Record could access the Preference manager directly. I suppose I could always instantiate Record with a pointer to the context from which it was created, but that's a lot to remember ;-)
So right now Record subclasses nothing. Any recommendations on what I can do to it to allow it to see the app context?
Thanks!
You could pass the Context object in the constructor. So whenever you try to use that class it will ask you pass a Context object and then use that to get SharedPreferences
For eg.
public Record(Context context)
{
mContext = context;
mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext)
}
You can also extend a class with Application, which will be global to the whole application and you can set the context in that class as a member variable and that context will be global to the whole application
Eg. class A extends Application{......}
You can do #Apoorv's suggestion or you can create another class that specifically stores the application context.
public class ContextResolver {
private static Context context;
public static void setContext(Context context) {
if (context == null) {
throw new IllegalArgumentException("Context must not be null");
} else if (context instanceof android.app.Activity) {
context = androidContext.getApplicationContext();
} else if (context instanceof android.content.Context) {
context = androidContext;
}
}
public Context getContext() {
return context;
}
}
Now you need to call setContext() in the first activity that will be launched once.
public class MyFirstActivity extends Activity {
public void onCreate() {
ContextResolver.setContext(this);
}
}
Now you can retrieve the Context from any part of your code. So in your Record class you can just do this:
mPreferences = PreferenceManager.getDefaultSharedPreferences(ContextResolver.getContext());

Using Resources in Exceptions

I have an app that uses custom Exceptions, such as this:
public class SomeException extends Exception{
private int iCode;
private String iMessage;
public SomeException(){
iCode = 201;
iMessage = **//Get the localized string R.string.error_201??**
}
#Override
public String getMessage() {
return iMessage;
}
#Override
public int getCode() {
return iCode;
}
}
Obviously, I want lo localize the error message. I have possible solutions but non of them satisfy me.
1) Pass "Context" to the constructor, and do ctx.getString(R.string.error_201)
--> Fail, as this Exceptions are sometimes thrown from MODEL classes, so they don't have a Context
2) Pass "Context" when retriveing the message in getMessage() function,
--> Fail, It's necesary to override the super method, to work as all other Exceptions.
Solution I have now: All activities in my app have this onCreate:
public void onCreate(...){
Utils.RESOURCES = getResources();
...
}
Very dirty code... I don't like the solution. My question is then,: is there a way to access the resources without the Context? And most important, How would an application such as mine solve this problem?
What about
public class MyException extends Exception {
private int iCode;
public MyException(int code) {
this.iCode = code;
}
#Override
public String getMessage() {
return "MyException code " + String.valueOf(iCode);
}
public String getLocalizedMessage(Context ctx) {
String message;
if (iCode == 201)
message = ctx.getString(R.string.error_201);
else if (iCode == 202)
message = ctx.getString(R.string.error_202);
// ...
}
}
Even if there was way to access context in different way, you should not do it. If you need to emit exceptions where you cannot pass Context, you should be able to access context before you display such error. I cannot see reason why you should create localized error messages from constructor. You can log to logcat not localized versions if you need. And where you want to display something in UI, you should have context at hand.
You can access only system wide resources without Context.
You need a Context, so I would suggest You to get it as soon as possible, and make it available through a static method or variable. You do the same thing in every Activity, but there is a cleaner method. You should make a custom Application, and override its onCreate() to make the resources public:
public class App extends Application {
private static Resources myResources;
#Override
public void onCreate() {
myResources = getBaseContext().getResources();
super.onCreate();
}
public static Resources getMyResources(){
return myResources;
}
}
The other thing you have to do is to set the Application in your manifest:
<application
android:name="{your_package}.App"
...
Now you can access the resources in all of your Activity without any preparation. Your custom Exception class could also use the externalized resources.

Categories

Resources