setTheme function not working on resume - android

I am trying to use setTheme function which basically set theme based on some DB value but the problem is once I have updated DB with theme to be set,I need to finish() the activity for theme settings to be implemented. code being -
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
settingsDBAdapter = new SettingsDBAdapter(this);
settingsDBAdapter.open();
setSettingsTheme(); <<------THIS LINE WILL SET THEME
setContentView(R.layout.layout_task_manager);
quickAddButton = (Button) findViewById(R.id.QuickAddButtonId);
quickAddTaskText = (EditText) findViewById(R.id.QuickAddEditTextId);
mDBHelper = new TasksDBAdapter(this);
mDBHelper.open();
fillData();
//code to create long press on any list item and calls onCreateContextMenu method
registerForContextMenu(getListView());
registerButtonListenersAndSetDefaultText();
}
public void setSettingsTheme(){
String currentTheme = settingsDBAdapter.fetchThemeSettings("theme");
Log.i(TAG,"settingsDBAdapter + currentTheme-->" + settingsDBAdapter + currentTheme);
//setTheme(R.style.HoloTheme);
if(currentTheme.trim().equalsIgnoreCase("holo")){
Log.i(TAG, "in holo<<<<<<<<");
setTheme(R.style.HoloTheme);
}else if(currentTheme.trim().equalsIgnoreCase("hololight")){
Log.i(TAG, "in hololight<<<<<<<");
setTheme(R.style.HoloLightTheme);
}else{
Log.i(TAG, "iin else<<<<<<<");
setTheme(R.style.HoloTheme);
}
}
I have also tried calling setSettingsTheme() function after overriding onResume() function still of no use.Log.i present in setSettingsTheme() function gives proper value always.
Can anyone please help me in my understanding. Thanks in advance,Kaushik

The documentation for ContextThemeWrapper.setTheme(int) says:
Set the base theme for this context. Note that this should be called
before any views are instantiated in the Context (for example before
calling setContentView(View) or inflate(int, ViewGroup)).
The Theme attributes are read in the Views constructors, so after changing the theme you'll want to recreate the UI. You can call finish() and then startActivity(getIntent()) in your Activity to restart it, or have to code a way to rebuild each and every View object.

Firstly, hat tip to Raffaele for pointing me in the right direction on this.
Also, I know this is an old post, so if there is now a better way to do this please let me know.
Anyway...
I ran into a similar issue trying to create a watch face for my Moto360. You can't change the theme instance that is referenced by the View hierarchy, but you can force that instance to take on the attributes of the theme you want to switch to. If you get a reference to your theme and call Resource.Theme.applyStyle(int,boolean), the attributes of the target theme get applied to the theme referenced by your View. After that a call to invalidate the View will update the UI with the new styling.
For example: (Somewhere in your activity ...)
Resources.Theme myTheme = SomeActivity.this.getTheme();
View myThemedView = SomeActivity.this.findViewById(R.id.myRootView);
myTheme.applyStyle(R.style.MyOtherTheme,true);
myThemedView.invalidate();
// Above, "true" clobbers existing styles, "false" preserves them
// and attempts to add in any new attributes.
Again, I did this on a watch face Service on a Moto360 without incident. I have not tried this on an Activity yet.
Resources.Theme.applyStyle(int,boolean)
You can see my code here (BatmanWatchFaceService.java).

Related

Android getResources(). where to define?

I have a string-array of main texts which is like words in dictionary and another string-array of sub texts which is like definition. Currently my code gets the resource from arrays.xml whenever call to the update is made and i think this is very unefficient and it feels like the response time is slow as well. However if I try to declare private String[] mMainArray = getResources().getStringArray(R.array.a_maintexts); anywhere outside this block, it doesnt work. Where should I put these getResources statements so that I only initialize my arrays once?
private void updateMainText(boolean next) {
mMainArray = getResources().getStringArray(R.array.a_maintexts);
mSubArray = getResources().getStringArray(R.array.a_subtexts);
if(next){
mCurrentIndex++;
}
else {
mCurrentIndex--;
}
mMainTextView.setText( mMainArray[mCurrentIndex]);
mSubTextView.setText( mSubArray[mCurrentIndex]);
}
Don't use private String[] mMainArray = getResources().getStringArray(R.array.a_maintexts); before onCreate() function is called. If you place this line above onCreate() i.e. make it global, it will mean that you are trying to access resources before the activity is even created which will give you NPE.
Thus as #laalto and #njzk2 suggested use it either in onCreate() or after onCreate() is called.
Generally, resource-based initialization in an Activity like this is best put into onCreate(). onCreate() is called only once. If there is a change to resources (for example due to orientation change), by default the activity is recreated.

Programatically changing the background of an ExpandableListView's group during onResume in Android

I've been having some trouble with onPause and onResume when implementing an ExpandableListView in my app. I may be doing this all wrong (in which case please tell me and I will endeavor to do it correctly) as I'm learning Android mainly from what I can find on the net. So, to jump into it, I've pretty much got my ExpandableListView working as I would like, but for one little bugbear. When I resume the activity (for example after the screen shuts off) I recreate my cursors (is that the best way to resume the activity? I was getting cursor errors before...) and then programatically expand the groups that were expanded when the activity was paused. Now ALL I want to do is change the background drawable for the expanded groups, but I can't seem to find a way to get their views. Any ideas?
#SuppressWarnings("unchecked")
#Override
protected void onResume() {
super.onResume();
String searchText = ((QueryString)this.getApplicationContext()).getQuery();
if((searchText == null || searchText.length() < 1))
if(!hasQuery)
refreshCursor();
else
searchCursor(queryString);
else
searchCursor(searchText);
ArrayList<Integer> ToExpand = (ArrayList<Integer>) ExpandedList.clone();
ExpandedList.clear();
for(Integer i : ToExpand)
{
listContent.expandGroup(i);
listContent.getChildAt(i).setBackground(getResources().getDrawable(R.drawable.listview_style_selected)); //NOT WORKING
}
}
EDIT:
What I really want is the View that I have just expanded programatically with listContent.expandGroup(i) so that I can then change the background drawable manually. Unfortunately getGroupView (where the background is normally changed) doesn't fire when you expand a group programatically so the background drawable remains unchanged. How can I get this view?
Call notifyDataSetChanged() in your adapter of your list. This should work. Maybe logging the "getChildAt" view helps.

EditText not automatically saved on screen orientation change

I read that Android automatically saves the content of EditText objects when an application is about to be stopped or killed. However, in my app the content of an EditText is lost when screen orientation changes.
Is it normal behaviour? Do I then have to manually save/restore its content with onSaveInstanceState/onRestoreInstanceState? Or is there an easier method to tell Android to save it end restore it?
Edit:
I create the EditText object programmatically, not in XML. This turns out to be related to the problem (see accepted answer below).
This is not normal behavior.
First and foremost, ensure that you have IDs assigned to your EditText controls in the layout XML.
Edit 1: It just needs an ID, period. If you're doing this programmatically, it will lose state unless it has an ID.
So using this as a quick & dirty example:
// Find my layout
LinearLayout mLinearLayout = (LinearLayout) findViewById(R.id.ll1);
// Add a new EditText with default text of "test"
EditText testText = new EditText(this.getApplicationContext());
testText.setText("test");
// This line is the key; without it, any additional text changes will
// be lost on rotation. Try it with and without the setId, text will revert
// to just "test" when you rotate.
testText.setId(100);
// Add your new EditText to the view.
mLinearLayout.addView(testText);
That will solve your problem.
Should that fail, you'll need to save and restore state yourself.
Override onSaveInstanceState like so:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("textKey", mEditText.getText().toString());
}
And then restore in OnCreate:
public void onCreate(Bundle savedInstanceState) {
if(savedInstanceState != null)
{
mEditText.setText(savedInstanceState.getString("textKey"));
}
}
Also, please don't use android:configChanges="orientation" to try to accomplish this, it's the wrong way to go.
could you use android:freezesText="true" in the xml layout?
The easiest way I found to save an object on onSaveInstanceState is to implement serializable and put in bundle
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("myObj", myObj);
}
where myObj class implements serializable and in onCreate() method
if (savedInstanceState != null && savedInstanceState.getSerializable("myObj") != null) {
myObj = ((MyObj) savedInstanceState.getSerializable("myObj"));
}
One possible cause is that you override onSaveInstanceState but you forget to call the same for super class
super.onSaveInstanceState(outState);
State of all views in activity is auto saved UNLESS you override this functionality. Even if this is obvious, mistakes are possible.
You just need UNIQUE ID for the edit text. Make sure if you dynamically add edit text, chances of having same id can cause not restoring the text.
Same way if you add in xml, use unique id. Hope it will help someone.
FYI: EditText by default having setFreezesText as true

Finding the current layout-xml file in focus using code

I am working on a practice android project, and I am trying to implement polymorphism ideas into my program. So far, I have created two different XML layouts, one for tablets, and one for phones. They both have a button, but I want the button to do different things depending on which layout it is in. I am using the onClick property, and both layout's buttons refer to the same method.
In my buttonClick method, I want to find out which layout is is currently being shown, and I am trying to do it this way,
public void buttonClick(View ve)
{
View v = getCurrentFocus();
//According to the API, this method returns the current view,
//but the Log Tag says that it is null, which should not be the case.
Log.i(TAG, "Current View is " + v.getContentDescription());
//I want to control what happens polymorphically using the next if-else
//clause,depending on the layout, I think that this part would work if
//the above code works alright.
if(v.getId() == R.id.TabletLayout)
{
TextView myText = (TextView)findViewById(R.id.textView);
if(myText.getText().toString().contains("World"))
myText.setText(R.string.ayo_android);
else
myText.setText(R.string.hello_world);
Log.i(TAG, "changing words");
}
else{
Log.i(TAG, "Creating new Activity");
myText = (TextView)findViewById(R.id.textView);
Intent intent = new Intent(this, NewActivity.class);
intent.putExtra("screenText", myText.getText().toString());
startActivity(intent);
}
}
Thanks.
That's not the way to do it. If you want them to do different things, have the refer to different click handlers. If they're widely different they shouldn't even have the same id. The entire idea behind the automatic layout overrides is that the application should never need to care which one to use.
In addition to Gabe's answer, getCurrentFocus() will not give you the layout of the activity. If you want the layout of the activity, you can use
View v = (View)findViewById(android.R.id.content);

Android: setImgVisibility() error

In my app I have a header with icon hidden, I have a adapter with a listview when I click the listview I go to a login screen using listener, when the login is successful is should come back to listview(adapter) and icon should get visible on header.
In the login activity I have the following code:
public void onClick(View v) {
String password = etPassword.getText().toString();
if(password.equals("guest")){
SearchAdapter.setImgVisibility();
} else {
//-----
}
finish();
}
In my adapter I am calling the setImgVisibility() as follows, but it is not working
public static void setImgVisibility() {
img.setVisibility(View.VISIBLE);
}
I am getting a Nullpointerexception near the line img.setVisibility(View.VISIBLE);
I am stuck here and don't know what I am doing wrong. Any suggestions or help is appreciated
I would imagine that img is null. You need to look at where this value is set and make sure happens before you call the method setImgVisibility.
Show more of your complete code for people to help further.
Additionally, i've just noticed you've used a static reference to your search adapter, you should be really careful using statics, especially where any referencing of images is concerned as images can be bound to the context, as such unless you nullify the static you will end up with a memory leak. (this used to be an old problem, not sure its still valid, but i would still avoid using a static reference).
Without more code we're not likely to be able to properly help you. For example are you switching activities when logging in? If you are, this won't work at all.
[given the comment below] If you switch activities then your activity containing the list view is going to be destroyed and then rebuilt then you navigate back to it. or it will at least go through the activity lifecycle. This means you can set the icon during the instantiation of the header img.
You could store your logged in state as a property of the Application or a preference. Grab this value when you set the header image and set the image accordingly.
your img object is null. Is your img object is same as View v then you can pass v in setImgVisibility() and then set v.setVisibility(View.VISIBLE)

Categories

Resources