Android getResources(). where to define? - android

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.

Related

Android Variable Optimisation

I want to optimize my Android application, but i don't know what is better?
First option:
public void function()
{
RelativeLayout rl = (RelativeLayout)findViewById(R.id.activity);
ImageView img = (ImageView)findViewById(R.id.image);
...
}
Second option:
RelativeLayout rl = (RelativeLayout)findViewById(R.id.activity);
ImageView img = (ImageView)findViewById(R.id.image);
public void function{
...
}
Which option use less resource? Global variables or local? (My program call this function every second)
In general, the second option is better. findViewById() can be fairly expensive if your view hierarchy is complex. It is better to call it once and store the results than to call it repeatedly.
Assuming the second option uses e.g. member variables, it won't even work. You need to call setContentView() e.g. in onCreate() before calling findViewById() and member variable initialization is performed before your onCreate() runs.
So the first one is better because it works while the other doesn't.
Other than that, at this level this smells of unnecessary micro-optimization. If you have performance issues, they are probably elsewhere.
Related: If you want to optimize findViewById() calls e.g. in an adapter where the same views are recycled over and over again, google for "android viewholder".

setTheme function not working on resume

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).

Suspend UI Layouts in Android

I have a bunch of code in a routine that looks a bit like this:
a.setContentView(R.layout.myLayout);
textview t1 = (TextView) a.findViewById(R.id.mylayout_t1);
t1.setText("Hello")
t1.setTypeface(font);
t1.setTextColor(colour);
t1.setTextSize(fontSize);
textview t2 = (TextView) a.findViewById(R.id.mylayout_t2);
t2.setText("Hello Again")
t2.setTypeface(font);
t2.setTextColor(colour);
t2.setTextSize(fontSize);
The problem I'm having is that before when the routine is called, the layout is done with all the fonts at the default font/size/colour and then they quickly change to the specified values, which is not very pleasant on the eye.
Is there some kind of command I can add to the beginning of the routine to suspend any layout, and then another command to resume at the end of the routine?
There are two ways:
1) Put your all code (you mentioned above) in onCreate() method and at last call t1.setVisible(true);
2) Put your code in the method in which you are creating your UI (like initUI() or something like that) and call this method before setting visibility to true.
Have you considered using XML to set the text style instead of doing it programmaticly. See this Android Dve Guide page for more on this topic.
Another (bad?) way might be to use XML to set the views visibility to false and when you have made your style changes, call t1.setVisibility(true). Haven't tried this one, so it might produce a similar, unwanted result.

Pulling data from one Tab Activity to another

Everything I've read about Intents talks about using them to push data, or to start one Activity from another Activity. I want to pull data from an Activity that's already running.
The Tab Layout tutorial at http://developer.android.com/resources/tutorials/views/hello-tabwidget.html illustrates what I want to do. (My app is doing some engineering calculations instead, but the tutorial code provides a good analogy to my app.) The tutorial creates an app with three tabs, and each tab hosts a separate activity.
To expand on the example in the tutorial, suppose I select an artist in the Artists tab/activity. I want to be able to select the Albums tab/activity and have it display all the albums featuring that artist.
It seems to me that I need to use an Intent to do this. All of the tutorials I've found assume that I would create a "See albums" Button in the Artists tab/activity, and that pressing the Button would execute an Intent that starts the Albums activity and passes artistName.
I DO NOT want to create that Button. Real estate on the Artists layout is precious, and I have a perfectly good Albums tab, AND the HelloTabWidget activity already contains an intent to create the Albums tab.
Besides, a user will want to skip back and forth between Album and Artist in order to change artist selections, and the tabs are a perfectly good way to do this. There's no need to complicate the UI with another button.
So how can I have the Albums activity PULL artistName from the Artists activity when the Albums tab is selected (or the Albums layout is displayed), rather than have the Artists activity START Albums and PUSH the artistName?
Equivalents I can think of from other programming worlds:
Global variables. Discouraged in Android devt, right? And if they do exist, what are they called?
A getter, like artistName = Artists.getArtistName(); . I get the feeling that it's not that easy.
Writing to, and reading from, a file - that is, mass storage or non-volatile memory. I don't need the artistName value to be permanent. It will be reset to null every time the user launches the application.
So how is it done in the Android world? Do I use an Intent - and if so, how?
Global variables were the right answer.
I thought Java discouraged their use, but a couple of links that appeared in the "Related" links on the right margin of this window mentioned them directly. One was "Android: How to declare global variables?" and the other was "how to pass value betweeen two tab in android". Both pointed to the Application Class as the place to define global variables and methods. Armed with this new knowledge, I found an article called "Android Application Class" on the Xoriant blog that expanded on the StackOverflow answers.
It's best to review those three links first. I need to add some tips to what those authors have said.
Your Application class has to be in its own separate file. (That might be a "duh" to some people, but not to everybody.) Here's a good framework for an example called Something.java:
public class Something extends Application {
// Put application wide (global) variables here
// Constants are final, so they don't have to be private
// But other variables should be declared private;
// use getters/setters to access them
public final boolean FEET = false;
public final boolean METERS = true;
private boolean units = FEET;
#Override
public void onCreate() {
super.onCreate();
// Put any application wide (global) initialization here
}
// Put application wide (global) methods here
public boolean getUnits() {
return units;
}
public void setUnits(boolean whichOne) {
units = whichOne;
}
}
I'm using Eclipse with the ADT plug-in, in Windows XP. Eclipse doesn't always behave properly if you edit XML code directly, so it's best to open AndroidManifest.xml, then select the Application tab and enter your application name in the Name field. You don't need to put a dot or period in front of the name. Just type in the name of your class, like "Globals" or "MyApplication" or whatever. (Note that this is the default application in your Manifest. You don't have to create a separate <application></application> tag.
This step may not be necessary on an actual Android device, but it was necessary for the emulator: you need to use the getApplicationContext() command in every onCreate() and every method that will be accessing the global variables and methods. I tried to put it outside of onCreate() with the rest of my activity wide variables, and it didn't work. Putting it inside every method seems wasteful, but both the emulator and the Android device work fine with it that way. Here's a sample showing how I used it:
public void fooBar() {
// Access to global variables and methods
final Something s = (Something)getApplicationContext();
// ...
// This next line demonstrates both a global method and a global variable
if (s.getUnits() == s.FEET) {
// do something with feet
} else {
// do something with meters instead
}
// ...
}
Those were the only hiccups I encountered. The three references that I have listed, taken together, are otherwise pretty complete.

Android: passing data between views

In my Android app, I have two custom view classes - PortraitClass and LandscapeClass. They both do the same thing. On running the app, the view class fetches some pictures from an SDCard and then maniputlates (skew etc) and displays them. The only difference between the two classes is that the layout of pictures is slightly different on the screen.
I have two display.xml files (one under layout folder and the other under layout-land). The one under the layout folder adds Portrait and the other adds the Landscape class.
On orientation change, I would like to send information (picture numbers and few bitmaps) from one class to another so I won't have to fetch all the bitmaps again and also so that I display the ones that were being displayed.
I find the parcelable thing kind of confusing. I tried following this_example, but I noticed that in onRestoreInstance, the Parcelable has null for the "mSuperState" and I get a classCastException # "SavedState ss = (SavedState)state". The integer (picture number) that I am trying to pass is there. I am not sure what I am doing wrong.
You could use a global singleton in the Application class. For example an "AssetManager" is available here:
public class YourApplication extends Application {
public AssetManager assetManager = new AssetManager();
#Override
public void onCreate()
{
super.onCreate();
}
}
You can then call it from another activity:
YourApplication application = ((YourApplication ) this.getApplication());
application.assetManager.someFunction();
Not sure if this is what you are looking for but my stuff always works in orientation change with onCreate(Bundle savedInstanceState). Mine is all text in edit text boxes though so I am not sure how it would work for you.
Also check this out about midway down under "Persisting State Information During Configuration Change"
http://www.devx.com/wireless/Article/40792/1954

Categories

Resources