How to use Strings from strings.xml in another class - java

I'm currently writing an App, it gets JSON from a website, and then lists the contents in a listview. Now since the API itself only returns names like this: "twisted_castle" instead of "Twisted Castle", I created a new class to substitute the generic names to the right names, which I previously added to the strings.xml.
Now I can get Strings via String test = getString(R.string.key) in the MainActivity, but since I created a new class for the Substitute to happen, I somehow can't use getString somehow.
I already discovered that I'll need to get/use the context of MainActivity somehow, but really any solution I found didn't work, and also I'm a bit irritated on how the whole context thing works.
Anyone can help me with this and maybe has a good explanation on how contexts work?

You can use Context as:
mcontext.getString(R.string.something);
all you have to do is init context in the class some where like:
static Context mcontext;
public void setmContext(Context context){
this.mcontext=context;
}
and call setmContext(this) from your activity or where ever you have context attribute

Related

Passing a variable from an activity to a class

I am knew to Android.
How do i pass a static variable from one activity to a class.
I have a list of buttons and when i click one button, i want to open a new activity and at thye same time, pass a variable relating to that class. I have tried using shared preferences but in vain. The string variable i would like to is is called url. This is the code i have from the class
public class AppConstant {
public static final String BASE_URL = url;
}
The BASE_URL will be used in other classes that is why it is static and i want it to stay that way.
shortest way would be to remove final keyword
public static String BASE_URL = url;
this will allow you to write to this field from any method in your app
AppConstant.BASE_URL = "abc";
note that AppConstant isn't proper name for such usage, BASE_URL isn't constant...
btw. keeping data in static field is a veeery poor aproach, don't do this... use Bundle for passing data between Activities, IPC communication (binding) for Services, SharedPreferences, SQLiteDatabase and probably few other methods...
Since other solutions haven't worked for you, here is something a bit different:
Make a saparate file named "ext" or something. inside make a public abstract class like so:
public interface ext {
HashMap <String, String> myHash = new HashMap<>();
}
This way myHash will be created when the app is launched and will live as long as the app does so when you move from activity to activity, you can add values this way and access them in the next activity:
ext.myHash.put("BASE_URL", url);
If it's static it shouldn't be in a Activity,
I assume you mean accessing a static variable from an Activity?
If so you can simply call AppConstant.BASE_URL in your Activity, if it is shown in red press Control+Enter to fix the import in Android Studio.
On the other hand, passing a variable from an activity to a class can simply be done via methods. So just call a method in the activity and use a String as a parameter like so
Otherclass.doSomethingWithString(urlInYourActivity)
But I assume the thing I mentioned at the start is what you want to do

how to properly pass context between methods to use database repository?

Ok this is a bit more theoretical question.
I have PlayerRepository. This is a class that is used to make actions on my SQLite database. I've implemented there actions like select, insert, update etc.
public PlayerRepository(Context context) {
super(context, com.fixus.portals.model.Player.class);
open();
}
super in constructor is cause PlayerRepository extends Repository which is also my class. The most important part of Repository is this one
public class Repository<T> {
protected static SQLiteDatabase db = null;
protected static MainHelper helper = null;
protected Context context;
private Class<T> type;
public Repository(Context context, Class<T> classz) {
this.type = classz;
this.context = context;
if(helper == null) {
helper = new MainHelper(context.getApplicationContext());
}
}
public static void open() {
if(db == null) {
db = helper.getWritableDatabase();
}
}
}
As you can see when I create the repository I'm opening DB if it wasn't open before. To do that I need to pass the Context of the application/activity. That is not a problem.
BUT sometimes I want to use my repository out side of an activity. In some kind of tool class that need to get data. So I have two ways that I can think about
I get the data in activity and pass it to my tool class/method so I don't need to use repository in it. This is not very flexible
I need to pass context to my tool class/method. But that means that every kind of operation need to receive a context and I'm not sure this is a good way
Am I missing something ? is there any better way to handle it ?
You always need a Context to access the SQLite database so what u could do is change the constructor of that specific tool class and pass a new instance of PlayerRepository as a parameter. This prevents your tool class of needing a context itself.
Imo if u have multiple classes using the database best approach is to create a new class whose only job is doing database actions and put all the needed action inside that one.
Just create an object of this database class with the Context of the current activity the to Tools and PlayerRepository constructors. This way neither your PlayerRepository or Tools classes need Context and both can make actions on the database.
Even if you should really need Context in PlayerRepository it is always best to keep all database related functions centralized in a single class.
I understand that this is an old question but still i'll write for those like me who will pass by this in future.
In order to get rid of the context problem with repository pattern used for accessing database you can implement DI (Dependency Injection) pattern in your project. There are many reasons to do such and that question illustrates one of them.
If you implement DI you would have only one instance of database repository amongst the entire module (or app). This instance would be created in a class which has context, and injected to those classes where needed.
One of the simpliest approaches for using DI is to use Dagger 2 library. All of the related information you could find on their site.

Dynamically set the authority of a ContentProvider

Perhaps the title is a bit misleading. My problem is that I have an Android library project which is shared between two standard Android projects: one for a free version of the app and the other for a paid version. The library currently has the code for a ContentProvider, including a contract class with several static String variables for things such as the URI and column names. Now I want the "authority" for the URI to change depending on which app is using the library. One solution that comes to mind is storing the authority as a string resource and loading that string at run-time into the static final String variable. However, I'm not sure how to do this as the contract class has a private constructor and no Context object in order to load the string resource. What other options are available to solve my problem?
Here's a better solution for those using newer versions of the build tools: make the authority relative to your application ID. You can do this automatically using ${applicationId}, which is expanded into your app's application ID during the build process.
<provider
android:name=".MyContentProvider"
android:authorities="${applicationId}.provider"/>
Let's say your application IDs are com.example.app.paid and com.example.app.free. When you build your app, the authority will become com.example.app.paid.provider and com.example.app.free.provider, correspondingly.
To reference the provider authority in your code, use BuildConfig.APPLICATION_ID + ".provider".
Using different authorities for the free and the paid version makes sense in case the user tries to install both versions.
I'm defining a different authority for the two versions in the manifest like so:
<provider
android:name="MyApp.MyProvider"
android:authorities="MyApp.MyProvider.free"
android:grantUriPermissions="true"/>
Then I configure the provider in an xml file (I use a special config.xml file because I have more configuration data like the provider authority, but you can use strings.xml of course):
<string name="my_provider_authority">MyApp.MyProvider.free</string>
The code retrieves the provider authority as any other string resource. To access string resources without a context use the application context. I'm using an application class to have access to the application context from anywhere in my app (there are two exceptions though):
public class MyApplication extends Application {
private static Context sContext;
#Override
public void onCreate() {
super.onCreate();
sContext = this;
}
public static Context getContext() {
return sContext;
}
}
Of course you need to define MyApplication in your manifest.
This allows you to access string and other resources from anywhere in your app.
There are two exception though:
ContentProviders. ContentProviders can be started before Application starts and so you won't have an Application context available. That's no problem though because ContentProviders get their own context through getContext().
Static code: the context might not be available outside the life cycle of Android components (Activities, Fragments, BroadcastReceivers, Services etc.). Static initializers that are relying on the application context are therefore not a good idea. But that's also not a real issue because using a context outside the life cycle of Android components isn't allowed anyway and static methods accessing a context would always be called from within that life cycle. E.g. if an Activity needs to know a ContentProvider's authority it would call a static method in your contract class and that call would be from one of the activity's onXYZ() methods like onCreate() or onStart() which would make sure that the context is initialized. So all you need to do is lazy initialize the variables in your contract class and make sure the caller does retrieve the variables only when it's clear that Application.onCreate() has been called before. Of course from within an activity you could retrieve the string resources directly. The real advantage of my method will become obvious when you need the resources in other classes/objects. These objects would still be tied to the life cycle of some Android component but you wouldn't have to pass around the context to all these objects, which is 1) very cumbersome and 2) very error prone when it comes to leaking the context which could lead to memory usage issues (one of the most common problems with Android apps).
Why change the authority at all? You're not required to export the provider, which means that nobody could even see the authority name except by deconstructing the app. Even then, they wouldn't be able to access the provider.
If it's for your own internal convenience, then I'd use the same authority but put different security on the URIs.
In short, your idea is interesting, but I wouldn't do it that way. Too much of a mess.

Register in android a session like value shared by all activity

How can I register data (like integer or poco objects) shared by all activity like the id of the user ? Have I to use a simple singleton or is there a special Android way ?
Note : I don't need to make that data persistant (no need of SharedPreferences or sqlite)
Thank you
You can create your own class that implements Application and specify this in your manifest file. In that case, every time you call getApplicationContext you will get a reference of your application that can hold any kind of information.
How to declare global variables in Android?
Sample code:
class MyApplication extends Application {
public void setMethod() {
//
}
}
((MyApplication)getApplicationContext()).setMethod()
The android way is to create a custom Application for your project. Then in onCreate of that application you initialize whatever you need, and for example from an Activity do something like:
((MyApplication) getApplication()).getMyData()
If using roboguice you can use a #Singleton injection which basically does the boilerplate of a singleton for you - that's much nicer.

Access Application class from class other then Activity

In my application I need data which is accessible for a few activities. I've read that a good solution is to use Application class for this. So I use it like this:
public class MyApplication extends Application {
private String str;
public String getStr(){
return str;
}
public void setStr(String s){
str = s;
}
}
and I can access this variable from activity like this:
MyApplication appState = ((MyApplication)getApplicationContext());
String str = appState.getStr();
It's ok, but I also have xml parser class:
public class MyXMLHandler extends DefaultHandler {
and if I try to do the same here
MyApplication app = ((MyApplication)getApplicationContext());
String str = app.getStr();
I'm getting The method getApplicationContext() is undefined for the type MyXMLHandler
How can I access my variable?
Well, usually an XML parser class should be independent of any special context. That means a developer should be able to use it no matter whether he's developing an application or a service or library or whathever.
The XML parser class should not make any assumptions as to the context it is being used in and where it gets parameters from (you'd restrict your parser to function only if it has access to an Application instance). The parser should not fetch its parameters, the parameters should be set by the caller.
You wouldn't want your XML parser class to show messages to the user, either, would you? Right: "What does an XML parser have to do with user interfaces?" Instead, you'd throw exceptions and make sure they are handled properly, for example depending on whether there's a user interface or not (logging).
So what you'd do is pass the parameters you need when constructing an instance of your XML parser. But you do not pass your application instance as a parameter (think again of dependencies), but you pass the necessary parameters from your application class.
In your example above:
MyApplication app = ((MyApplication)getApplicationContext());
MyXmlHandler handler = new MyXmlHandler(app.getStr());
You should really make sure to keep "tool stuff" separate from anything that would prevent you from using it universally. What would happen if you wanted to use your XML Parser class in another project where your parameter is not provided by the application context but some other class?
I'm sure that you can have a week-long discussion about object-oriented design and how things should be done - but that's basically how I'd do it...

Categories