I've just started with Android Development. Now, I want to make an enumeration. Each enum-object within that enumeration, I want to assign a name to. I want to get that name from my project resources (res/values/strings.xml).
But from within the enumeration type, I can't call getResources().getString(R.string.string_name).
Is that because the enumeration doesn't extend an activity or something?
How can I fetch the strings from the resources anyway?
Thanks!
P.S. The enumeration is not nested within a class. If it is possible, I want to keep it as a seperate file.
getResources().getString() is simply a shorthand for getActivity().getResources().getString().
So getResources() still rely on having a context (activity, fragment, context, etc).
To overcome this, i personally extended the Application class and made a public static Context available, so you can always access resources and such in your entire application, no matter if you're in an activity or a POJO.
Example:
public class MyApp extends Application {
public static Context context;
#Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
}
With this, you can always call:
MyApp.context.getResources().getString(xxxx);
Enumerators are implicitly static. As in when they are created, your activity and therefor its Context is nowhere to be found. If there's no Context, there are no Resources either.
Perhaps what you want to use is a static class with custom constructor instead of an enumerator. Example:
private static class MyConstants {
private Resources mResources;
public String constant1;
public String constant2;
public String constant3;
public MyConstants(Context ctx) {
mResources = ctx.getResources();
constant1 = mResources.getString(R.id.string1);
constant2 = mResources.getString(R.id.string2);
constant3 = mResources.getString(R.id.string3);
}
}
MyConstants mConstants;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_book);
mConstants = new MyConstants(this);
Log.e(TAG, mConstants.constant1);
...
}
Related
I started to learn MVP but I have a few questions related the SharedPreferences, as far as I know if I want to save a value in the sharedPreferences I need to pass this value to the presenter and the presenter calls the model to save the value, the same logic I would apply if I want to get or remove a value from the sharedPreference, but how is the best way to do that if I shouldn't pass the Context?
I sae a few code and the people used to pass the Context in the constructor method direct to the Model, but I still don't think that's a good idea.
Do you guys have any ideas?
Thanks,
Thales
Android specific imports should never exist in the Presenter if you want to keep it unit testable.
What you can do is, make an abstraction layer above SharedPreferences let's call it Cache, it would be an interface with all the needed caching methods, you would then provide a concrete implementation of it using SharedPreferences.
Here is a quick illustration of the idea:
interface Cache {
// Your caching methods
}
class CacheImpl implements Cache {
private SharedPreferences sharedPrefs;
public CacheImpl(Context context) {
// Takes a context to init sharedPrefs.
}
// implements all of Cache's methods
}
Then you would pass a reference for that implementation to the Presenter's constructor (better yet using DI to inject it to your presenters constructor):
Cache cache = new CacheImpl(myContext); // Naturally that would be an activity context
MyPresenter presenter = new MyPresenter(cache);
Then in your presenter you would receive that instance in the constructor:
private Cache cache;
public MyPresenter(Cache cache) {
this.cache = cache;
}
You can then use the cache variable without knowing about it's concrete implementation nor should you provide it a context.
Create a Storage class Object inside View and pass the context inside Storage Class constructor.
Then pass this storage class object in presenter (constructor) from View class.
Then whenever you need to save or get some data from your presenter - Then simply call the method of storage class from the object you have passed.
This way you will not need to send the context to your presenter.
View class
public class ViewClass extends ActionBarActivity {
private MyPresenter presenter;
private MyStorage storage;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
storage = new MyStorage(this);
presenter = new MyPresenter(this,storage);
}
}
MyStorage Class
public class MyStorage {
private Context mContext;
public MyStorage(Context context) {
this.mContext = context;
}
public void saveData(String data){
}
public String getData(){
return "";
}
}
MyPresenter class
public class MyPresenter {
private final ViewClass mView;
private final MyStorage mStorage;
public MyPresenter(ViewClass viewClass, MyStorage storage) {
this.mView = viewClass;
this.mStorage = storage;
}
}
So I am using getdefaultsharedpreferences in a method called onLoadFinish (it's from a pdf library from android).
Here's the code:
public void onLoadFinish(DocumentState.OPEN state) {
//some irrelevant code here
SharedPreferences pref= PreferenceManager.getDefaultSharedPreferences(getActivity());
String text = pref.getString("example_list","");
int foo = Integer.parseInt(text);
goToPage(foo);
//some irrelevant code there
}
So the main task of the code is to get a value from my example_list preference (a string), turn it into an integer and put this integer into my goTopage();, which makes the app jump to a certain page in my pdf document.
The problem is this part:
PreferenceManager.getDefaultSharedPreferences(getActivity())
getActivity isn't working. I have tried getApplicationContext() aswell. What should be in the brackets of getDefaultSharedPreferences()?
getDefaultSharedPreferences expects an instance of Context class. getActivity method is declared in the Fragment class, so, unless your onLoadFinish method is declared in any Fragment successor, you can't use it. Per your comments, if I understood you correctly, onLoadFinish is declared inside Activity. If so, you can just use this keyword to pass the context, because Activity is a successor of Context. If this method is declared in another class, you should pass context to it, via constructor injection, for example.
EDIT Example of providing context via constructor injection.
Let's say you have the following interface:
public interface MyInterface {
void myAction();
}
And you have a class, which implements it and requires an instance of Context to do the work:
public class MyClass implements MyInterface {
private WeakReference<Context> mContext;
public MyClass(Context context) {
this.mContext = new WeakReference<Context>(context);
}
#Override
public void myAction() {
Context ctx = mContext.get();
if (ctx != null){
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
//do stuff
}
}
}
As you can see, Context instance is injected via constructor and we don't keep a strong reference to the context (actually it depends on specific needs). This class can be used inside Activity in the following way:
MyClass myClass = new MyClass(this);
Or inside fragment:
MyClass myClass = new MyClass(getActivity());
PreferenceManager should be used with a PreferenceActivity.
Just use context.getSharedPreferences("pref_name", Context.MODE_PRIVATE);
getDefaultSharedPreferences required your application context a parameter,
Try this,
public class MyActivity extends ActionBarActivity
{
......
.......
PreferenceManager.getDefaultSharedPreferences(MyActivity.this);
......
......
}
I have a static class containing overlay items that is called by my main class and then added to an overlay itself.
I can get this to work without image types but I would like to use them, however when I do I get the following error:
Cannot make a static reference to the non-static method getResources() from the type ContextWrapper
I have tried quite a few things to overcome this, by following some guides I have tried to add:
private static Context context;
public void onCreate(){
super.onCreate();
Mine.context = getApplicationContext();
}
public static Context getAppContext() {
return Mine.context;
}
I have also ensured that I have the class in question as an application in the manifest.
The class is as follows:
public static ArrayList<ExtendedOverlayItem> array = new ArrayList<ExtendedOverlayItem>();
public ArrayList<ExtendedOverlayItem> getMine() {
return array;
}
public static void addMe() {
Drawable myDrawable = getResources().getDrawable(R.drawable.draw); //This is the line that doesn't work
ExtendedOverlayItem myMarker1 = new ExtendedOverlayItem(
"sample", "sample", new GeoPoint(85.123456,
-14.123456), null);
myMarker1.setMarker(myDrawable);
myMarker1.setDescription("This is a test description");
array.add(myMarker1);
}
private static Context context;
public void onCreate(){
super.onCreate();
Mine.context = getApplicationContext();
}
public static Context getAppContext() {
return Mine.context;
}
I have tried adding the following :
myMarker1.setMarker(Mine.getAppContext().getResources().getDrawable(R.drawable.example));
But I still get null pointer errors when calling from the main method, If I leave the images out, it is called correctly.
In the main method I call this class as follows:
Mine.addMe();
ItemizedOverlayWithBubble<ExtendedOverlayItem> thisThing = new ItemizedOverlayWithBubble<ExtendedOverlayItem>(this, Mine.array, map);
map.getOverlays().add(thisThing);
Any advice greatly appreciated.
In Java static method can not access any non-static method or variable.
One of the basic rules of working with static methods is that you can’t access a nonstatic method or field from a static method because the static method doesn’t have an instance of the class to use to reference instance methods or fields.
for more information Document
here is good example how to access them
if you have context set before this line
Drawable myDrawable = getResources().getDrawable(R.drawable.draw);
then use
Drawable myDrawable = context.getResources().getDrawable(R.drawable.draw);
as add me is static method and can not get context for getResources()
EDIT:
getResources() is called on context. and in your code you are calling it from a static method but static method can not access nonstatic method of your applications context.
so you made a static object for context and stored your context in it.
but have you checked that the context you set is not null and set before calling above line?
I need to get a reference to the shared prefs from inside an abstract class called A that does not extend anything.
I cannot pass a Context object to this class to get the shared prefs because being abstract, I don't instantiate it. I created class A to be extended by other POJOs that share a single attribute, which is the uuid. The UUID is generated once in the app on its first run, which is why I store it in the shared prefs. In class A's constructor, I'm hoping to set the uuid based on what is in the shared prefs.
public abstract class A {
private String uuid;
public A() {
// this is how I'm hoping to use the shared preferences
this.uuid = sharedPrefs.getString("KEY_UUID", "null");
}
// getter and setter
}
One suggestion I found is to extend Application, say in a class called App, and include an attribute android:name=".App" in the <application> tag in the manifest. I imagine App will be written like this:
public class App extends Application {
private static App app;
public void onCreate() {
this.app = this;
}
public static App getApp() {
return app;
}
}
...so that from inside class A, I can do this:
this.uuid = App.getApp().getSharedPreferences("prefs_name.txt", Context.MODE_PRIVATE).getString("KEY_UUID", "null");
However, doesn't the non-final static field app lose its reference to the App and become null when Android kills off the process or when the phone restarts? How can I get a reference to the shared prefs without using this method? Or should I just manually write the UUID to a file?
Modify your App class to something like this:
public class App extends Application
{
private static Context context;
#Override
public void onCreate()
{
super.onCreate();
App.context = getApplicationContext();
}
public static Context getStaticContext()
{
return App.context;
}
}
I cannot pass a Context object to this class to get the shared prefs because being abstract, I don't instantiate it.
Sure you can. Put Context as a parameter on the constructor. Or, put SharedPreferences as a parameter on the constructor, if you prefer. Your subclasses' constructors will need to take the same parameter and pass it to the super() call.
However, doesn't the non-final static field app lose its reference to the App and become null when Android kills off the process or when the phone restarts?
Well, the whole process is gone. Saying that it loses "its reference to the App and become null" is akin to saying that a person at ground zero of a nuclear blast will get a sunburn just prior to being vaporized -- while probably true, the point is a bit moot. :-)
I have a couple activities in my app that I would like to utilize shared preferences. Initially, I created a method in each activity to utilize SharedPreferences, which worked fine. However, since there are multiple activities that use the same data, I’m basically tucking similar methods in multiple places. So it seemed like it made more sense to create a class specifically for the purpose of handling all these methods.
Unfortunately, I don’t understand how to do it properly.
This won’t compile, because it says “getSharedPreferences is undefined for the type AppPrefs.”
public class AppPrefs {
public void foo() {
SharedPreferences settings = getSharedPreferences("MyAppPrefs", 0);
}
}
Finally, I thought, maybe since SharedPreferences is an interface I could do this, but then I’d have to implement the inherited methods. I have no reason to Override any of those methods, so there is no reason to do this either.
public class AppPrefs implements SharedPreferences {
public void foo() {
SharedPreferences settings = getSharedPreferences("MyAppPrefs", 0);
}
}
What makes sense to do here? Is there a concept am I missing? Could anyone elaborate and explain? Thanks.
Pass your context into your preference getter.
public class AppPrefs {
public static void foo(Context ctx) {
SharedPreferences settings = ctx.getSharedPreferences("MyAppPrefs", 0);
}
}
Now just pass in this from an activity class to foo()
If the preferences are global to the application, you can use PreferenceManager.getDefaultSharedPreferences(); when you need to access the common preferences. If the preferences are specific to a subset of Activities, you have a few different options:
You can make a Activity subclass that is extended by all classes which need to access the preferences:
public abstract class AbstractFooActivity extends Activity
{
protected SharedPreferences getFooPreferences()
{
return getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
}
private static final String PREFS_NAME = "FooPrefs";
}
public class AFooActivity extends AbstractFooActivity
{
public void aMethodThatNeedsPrefs()
{
// ...
SharedPreferences myPrefs = getFooPreferences();
}
}
Or, if like me, you'd rather not mess with the class hierarchy you can simply create a common constant value for the group of activities which need to access the preferences. This is useful in the situation where you have class outside of the Activity hierarchy that need to access the preferences. For instance, a Service.
public final class FooConstants
{
public static final String FOO_PREFS_NAME = "FooPrefs";
}
public class AFooActivity extends Activity
{
public void aMethodThatNeedsPrefs()
{
// ...
SharedPreferences myPrefs = getSharedPreferences(FOO_PREFS_NAME, MODE_PRIVATE);
}
}
public class AFooService extends Service
{
public void aMethodThatNeedsPrefs()
{
// ...
SharedPreferences myPrefs = getSharedPreferences(FOO_PREFS_NAME, MODE_PRIVATE);
}
}
The second method is slightly less encapsulated, but puts fewer restrictions on the object hierarchy, which is a good tradeoff in my opinion.