Get Theme Attribute from Application Class - java

I have been using a method to obtain color attributes from the current Context:
public static int getColorAttribute(Context context, #AttrRes int attr) {
final TypedValue value = new TypedValue();
context.getTheme().resolveAttribute(attr, value, true);
return value.data;
}
It works perfectly, but when I tried using it in my class that extends Application it returns 0. In most cases I would call the method like so:
int colorAccent = Util.getColorAttribute(this, R.attr.colorAccent);
This would return the "colorAccent" that I set in themes.xml as my AppTheme in my Manifest. But in the Application class I had to call getApplicationContext() instead of this. So I switched one of my other instances of the method in an Activity to getApplicationContext() as well and it returned 0. I also tried getApplication() and getBaseContext() with the same result.
I was wondering if there is a way to get a color from the application theme in the Application class. Or if not, why getApplicationContext().getTheme() does not seem to return the application theme.

Can you try to set the theme yourself?
getApplicationContext().getTheme().applyStyle(R.style.someTheme, true);
and then in styles have your theme that is a child of some theme you want in android. Also this method should be frowned on as themes are meant to be accessed from activity context. application context is not complete for UI tasks.

Related

Android: How to use string resource from xml file in property of customized preference?

I've implemented a custom seekbar preference, using this site - seekbar preference and it works just fine. Now I want to add values to the seekbar's customized properties from the string.xml file instead of hard-coding them:
Instead of writing customseekbar:unitsRight="Seconds" I want to have a string resource like <string name="units">Seconds</string> and use it like this: customseekbar:unitsRight="#string/units". I've tried to implement this guide. My relevant code is:
attrs.xml
<resources>
<declare-styleable name="CustomSeekBarPreference">
<attr name="unitsRight" format="reference|string"/>
</declare-styleable>
And the constructor -
CustomSeekBarPreference.java
public class CustomSeekBarPreference extends Preference implements SeekBar.OnSeekBarChangeListener {
private static final String APPLICATIONNS="http://CustomSeekBarPreference.com";
public CustomSeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.CustomSeekBarPreference, 0 ,0);
mUnitsRight = a.getString(R.styleable.CustomSeekBarPreference_unitsRight);
a.recycle();
}
and the layout -
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:customseekbar="http://CustomSeekBarPreference.com" >
<com.x.sharedpreferencestestapp.CustomSeekBarPreference
android:key="1"
android:defaultValue="30"
android:max="100"
customseekbar:min="0"
android:title="Default step"
customseekbar:unitsRight="#string/units"/>
</PreferenceScreen>
But as you can see, I get 'null' instead of the right value:
Even if I change the value to a fixed string instead of string resource, like customseekbar:unitsRight="Seconds" I still get the same result. And just to make it clear - if I stick to the original code of the seekbar preference: mUnitsRight = getAttributeStringValue(attrs, APPLICATIONNS, "unitsRight", "defaultValue") it works, but not with string resource.
You're getting null for that attribute value because of the namespace you've declared for it in the layout XML - http://CustomSeekBarPreference.com.
As far as I'm aware, the obtainStyledAttributes() method can only pull attributes that are in the standard Android resource namespace – http://schemas.android.com/apk/res/android – or your app's resource namespace, which is http://schemas.android.com/apk/res/ plus the app's package name. Attributes in any other namespace will be ignored, and will not be in the returned TypedArray, which is why you get null no matter if the value is a hardcoded string, or a resource reference.
In the example you're following, they've used a similar non-standard namespace, but they're pulling the value directly from the AttributeSet, specifying that namespace in the getAttributeValue() call thereon. I can't say that I've seen this particular method often used in this manner, and the only benefit I can see to it is that it saves you from having to define your own custom attributes, which is a rather trivial task.
There are a couple of ways to fix this.
Move those layout attributes into your app's namespace, and define an attr resource for each.
This is the method demonstrated in the developer page you've linked, and is probably the most common and familiar way to implement custom View attributes.
First change the namespace declaration in the layout to:
xmlns:customseekbar="http://schemas.android.com/apk/res-auto‌​"
(The res-auto segment is a convenience that will cause the actual namespace name to be appropriately constructed with the current package name, as previously described.)
With your posted setup, this will then cause an error with customseekbar:min, since you've not defined min as an attribute resource (attr) in your app. You can simply define that attr, and then handle it the same way you're handling unitsRight; i.e., retrieve its value from the TypedArray returned from obtainStyledAttributes(). You would do the same for any additional custom attributes you might need.
Modify the getAttributeStringValue() method in the CustomSeekBarPreference example to handle resource references as well.
This may be the simpler option, as far as modifying the given example, but directly accessing the AttributeSet values prevents those values from being adjusted for any theme or style that you might wish to apply. If that's not a concern, then the necessary changes are rather simple.
In the modified method, we just need to first check if the attribute value is a resource value, using AttributeSet#getAttributeResourceValue(). If that method returns a valid identifier, we retrieve the actual value with Resources#getString(). If not, we treat the attribute value as a plain string.
private String getAttributeStringValue(AttributeSet attrs, String namespace,
String name, String defaultValue) {
String value = null;
int resId = attrs.getAttributeResourceValue(namespace, name, 0);
if (resId == 0) {
value = attrs.getAttributeValue(namespace, name);
if (value == null)
value = defaultValue;
}
else {
value = getContext().getResources().getString(resId);
}
return value;
}
Using this method, you would not need to define your custom attributes, and the layout namespace can remain as you have it in the posted snippet.

Context argument and Identifier in Android API

When I check for camera existence on Android phone, I start with the following function:
public static boolean deviceHasCamera(Context context)
{
if ( context.getPackageManager().hasSystemFeature(Packa geManager.FEATURE_CAMERA))
return true;
else
return false;
}
My question is, why should I pass context as an argument and what is Context Identifier?
Context provides you access to system resources. Without having a Context you cannot get many things from your system such as package manager, strings, colors, dimensions, system services such as LayoutInflater and so on. You also can't start any android component such as Activity or Service. So you should always think about it when designing the architecture of the app.
There are 3 types of context in android: Activity, Application, Service. Also, there are BroadcastReceiver and ContentProvider that don't extend Context directly but they have contexts inside.

How can I use my global variable inside an Adapter class? Android

Hi i'm trying to pass a value by using Global Variable. I have created a class file where it is extended to Application and then add it on my Manifest.
public class MyApplication extends Application {}
After that I had created an Adapter Class which is extended to BaseExpandableListAdapter, I've search on how to set and get the global variable i've created and found this
((MyApplication) getActivity().getApplication()).setMy_id(my_id);
and to be able to get the value I use this
Integer my_id = ((MyApplication) getActivity().getApplication()).getMy_id();
In my Fragments, I can use my getMy_id() method but when putting it inside the BaseExpandableListAdapter, I'm having an error in getActivity(). I already tried using this but still it says Cannot resolve method getApplication(), is there any other way to get the value of my global variable.
I'm doing this because I'm trying to use Cursor for my ListView. I wanted to create a Expandable ListView where the data is from my database and my Cursor have a parameter for it's WHERE condition where my data in my global variable will be used.
The reason why I'm using it as a global variable because I use this data in different Fragments where it is not static it changes its value depends on the selected item.
Thank you in advance.
You need to have a constructor in your class that extends BaseExpandableListAdapter. The defined constructor should receive a parameters of Context type. Here is the example -
private Context mContext;
public YourExpandableListAdapter(Context context) {
mContext = context;
Integer my_id = ((MyApplication) context.getApplicationContext()()).getMy_id();
}
Now create an instance like this in your activity -
YourExpandableListAdapter ob = new YourExpandableListAdapter(this);
This should work.
I'm not really sure what you're trying to achieve but whatever it is you're doing seems hacky to me! As per answering your question, getApplication() needs a context, so when you do
((MyApplication) getActivity().getApplication())
You are essentially using the activitiy's(getActivity()) context. And you cannot call getActivity() in an Adapter class. Try passing the context of your activity from the activity to the adapter in your constructor, something like.
MyAdapter myAdapter = new MyAdapter(this); //This line will be in your activity, and this will be the instance of your activity
And your adapter constructor would look something like
public MyAdapter(Context context){
//Use this context to get the application instance, something like
Integer my_id = ((MyApplication) context.getApplication()).getMy_id();
}
For Me, all above didn't work. try this:
((MyApplication) context.getApplicationContext()).getMy_id();

Static Context from Activity.onStart()

I am trying to generate a notification from a class, Utilities.java, outside of the subclass of Context. I've thought about providing a SingletonContext class and have looked at posts ike this. I'd like to be able to return != null Context object since the notification can be generated at any given time because it is generated from a messageReceived() callback.
What are there downsides to doing something like this:
public static Context c;
public class MainActivity extends Activity{
#Override
public void onStart()
super.onStart()
c = this.getApplicationContext();
}
//other method somewhere outside this class
public Context getContext(){
return MainActivity.c
}
I don't think it would be any different than putting this on the onCreate(), however, it guarantees that the context is up to date when the activity starts.
The Context keeps a reference to this activity in memory, which you might not want. Perhaps use
this.getApplicationContext();
instead. This will still let you do file IO and most other things a context requires. Without a specific reference to this activity.
Maybe you should overwrite the onResume Method.
If you open a new activity, and switch back, the onStart method will not getting invoked.
Android Lifecycle: doc
BTW: I read about problems with ApplicationContext using a dialog or toast, so if you use the context to create on of these you should use your Activity as context.

Android Application class - lifecycle of field members

I have Android application and own Application derived class holding some internal data.
Among other there are some string fields. The problem is that if I put the application in foreground, work on other application, switch back to my app again, the app may be restarted because it got killed by system. Unfortunatelly the Application object seems not to be created again because the onCreate method of application object doesn't get called and all fields are set to null. My Activity gets recreated but all Application's object fields are null. When is the Application.onCreate method called? How to handle it?
there is no onCreate that you can register to.in later API's there's a way to register to the Activity lifecycle functions. and then you can do what ever you want.
basically, what you should do is use SharedPrefrences for storing information.
what I would do is:
class MyApp extends Application {
private static String someResource = null;
public static String getSomeResource(Context context) {
if(someResource == null) {
SharedPrefrences prefs = (SharedPrefrences)
context.getSystemService(Context.SHARED_PREFRENCES);
someResource = prefs.getString(SOME_RESOURCE, null);
}
return someResource;
}
Application onCreate() will called only for one time during its life-cycle, i.e.. only when application is started.
As suggested by thepoosh below answer is valid ,if your application is killed,still the data is saved in shared preference.

Categories

Resources