I am learning android development from a course by Udacity.While I was going through the Lesson 2,there came a situation where we had to create multiple Textviews,set the text from previously created ArrayList of strings and add those Textviews to Linear layout.
Common code:
ArrayList<String> words = new ArrayList<String>();
words.add("one");
words.add("two");
words.add("three");
words.add("four");
words.add("five");
words.add("six");
words.add("seven");
words.add("eight");
words.add("nine");
words.add("ten");
LinearLayout rootView =(LinearLayout) findViewById(R.id.rootView);
Now what they did:
for(int i=0;i<10;i++){
TextView wordView=new TextView(this);
wordView.setText(words.get(i));
rootView.addView(wordView);
}
What I did:
ArrayList<TextView> wordView = new ArrayList<TextView>();
for(int i=0;i<10;i++)
{
wordView.add(new TextView(this));
wordView.get(i).setText(words.get(i));
rootView.addView(wordView.get(i));
}
Now,my question is weather my way to approach the task has more memory overheads than their way?
I feel my code is better because I have reference to each TextView even after the loop.
No difference. In both cases TextView instances could not be garbage collected, so memory foot print is equal.
because I have reference to each TextView even after the loop.
If you don't really need these references then it's just senseless. It's not memory related advantage.
Your code looks good. But I don't see a point on having 10 the same TextViews. I would consider using a listView or recyclerView if you are using it as a list and thinking about optimising your code.
But still your code is fine.
It doesn't matter performance wise.. Just like you said:
I feel my code is better because I have reference to each TextView even after the loop.
If you need that, do it..
Related
Hey I am making an android app that will have ~256 buttons.
Because I dont want to write the very same code for everyone of these I thought it might be possible to realize an easier solution via arrays. My approach in the onCreate to set the listeners was:
1 for (int i=1; i<32; i++)
2 {
3 button[i] = (Button)findViewById(R.id.button[i]);
4 button[i].setOnTouchListener(this);
5 }
I set the Button[] like that: Button[] button=new Button [64];
Now, eclipse tells me in line 3 "button cannot be resolved or is not a field" and it just underlines the word "button", so I think it ignores/just does not recognize the [i] (array)-stuff.
The rest of my code seems to get on with that perfectly because it gets recognized as an object (correct me if I said that wrong) but the findViewById() doesn't get on with it ..
Thanks for the replies, Alex
You can't do what you proposed in your solution. A better way to go about it is to add the buttons dynamically in code. For instance,
View parentView = (LinearLayout) findViewById(R.id.parentView);
// declare button array above
for (int i=1; i<32; i++)
{
Button btn = new Button(context);
// EDIT: adding a background resource
btn.setBackgroundResource(R.layout.button_layout);
btn.setText("This is my text");
btn.setOnTouchListener(this);
button[i] = btn;
}
User "Horschtele" answered it in a perfect way but he deleted his answer on his own (don't know why).
Horschtele, if you read that, I just want to say that this solution is just perfect!
I have to (or at least I think I have to) do this for every tableRow but this saves me an infinite amount of time. Thanks again Horschtele (are you german? :))
My modified version of Horschtele's answer if you already have your buttons in a table:
ViewGroup container = (ViewGroup) findViewById(R.id.tableRow1);
for(int i=0; i<container.getChildCount();i++){
System.out.println(container.getChildCount());
Button button = (Button)container.getChildAt(i);
button.setOnTouchListener(this);
}
(don't wonder about the println, you can easily check if the system correctly recognizes the container you are refering to).
If you did it my way with an array of Button then this is the way to go:
button[i] = (Button)container.getChildAt(i);
button[i].setOnTouchListener(this);
Is there a quicker or shorter way to initialize all view in my layout than this:
row2[0] = (RelativeLayout) findViewById(R.id.ll22);
row2A[0] = (RelativeLayout) findViewById(R.id.ll22alt);
row2B[0] = (RelativeLayout) findViewById(R.id.ll22blank);
mOffsiteDataBackup[0] = (TextView) findViewById(R.id.ll22_backup);
mRam[0] = (TextView) findViewById(R.id.ll22_ram);
mCpu[0] = (TextView) findViewById(R.id.ll22_cpu);
mHdd[0] = (TextView) findViewById(R.id.ll22_hdd);
mOs[0] = (TextView) findViewById(R.id.ll22_system);
mStatusIcon[0] = (ImageView) findViewById(R.id.ll22_image);
.
.
.
It is really annoying to write lot of lines only to find views. Until I find all of them and initialize some listeners, my onCreate has more than 400 lines, which is something I certainly don't want.
Thanks for your tips !
Any way you do it it's going to be around the same amount of typing, in some cases even more. 50> an extreme amount of views in an activity...
The only way I can think of making this smaller is splitting them up into Fragments and use the updated framework... 70 elements shouldn't be in one ui.. a ui is meant to be simple and easy to use. Not with lots of elements to it that distracts the user from the main task they want it for.
If few UI elements are functional unity(like your progresBar and textView), you can create custom view with these elements. That makes code is much more clear, especially if you use more instances of this view in one activity.
i would like to ask a lot of questions about how this whole id system works in android. I looked up the View documentation, but the description was too shallow for my taste.
Is there a pattern, how the IDE (Eclipse/Netbeans) generates the ids
when i use android:id="#+id/..."? Or is it completely random?
If i set ids programmatically, then will it be found by the Context
classes findViewById() function?
If the answer for the previous question is yes, then if i want to
create a large amount of Views, but i want them to have distinct ids
for later identification, then wich one is better to use? (To answer
this question, it would be really useful to know the answer for the
first two)
For example generating random ids in the largest possible range:
Random random = new Random();
for(int i=0; i<100; i++)
{
View view = new View(someContext);
view.setId(random.nextInt(Integer.MAX_VALUE));
}
Or setting the ids in some sort of order, for example:
final int addToId = 5670;
for(int i=0; i<100; i++)
{
View view = new View(someContext);
view.setId(i+addToId);
}
Also i would like to know, what happens, when you use a
LayoutInflater for example to populate a ListView using a
pre-defined xml layout for every item in the list. Then you get your
sub-views in the getView() function by the findViewById(). So i
assume, that all the identical Views across your listitems have the
same id. If so, then is it a good practice to use the tag
attribute to distinguish the items in an inflated layout?
Any clear explanation for these question would be highly appreciated!
#+id/.... creates an id value that lives within the applications namespace. Contrast this with #android:id/.... which lives in the android namespace.
When you set the id in code and add the view element to the layout it will then become available to access through the code. You won't be able to reference it from the xml
Not sure you want to be using random to generate your ids? think sequential would be better but even then what is the point of a random id? How do you know which view you are referring to?
Definitely use the tag option and look to use the ViewHolder pattern for smoother list scrolling. You could add the id to the view holder class if you need access to it but it would be available anyway through the data set being used to populate the list. A quick search will give you plenty of examples for this.
I have a Service that sends an Intent to my Activity every 0.1 seconds. I use it to update a custom implementation of a Chronometer. Here everything goes right. The problem comes when I want to update 14 TextView I have in a TableView inside a Fragment in my Activity. Here the app is very slow.
The method in my Activity where it receives the Intent from the Service:
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
long milis = intent.getLongExtra("milis",0);
if( mFragment != null)
mFragment.Update(milis);
}
};
The code inside the Fragment where I update the TextViews:
public void actualizarTiempoJuego(long milis){
// Se recuperan los tiempos acumulados y se aumenta la cantidad pasada como parámetro
for(int i=0;i<7;++i) {
long mCurrentMilis1 = mVectorMilis1.get(i);
long mCurrentMilis2 = mVectorMilis2.get(i);
TextView1 t1 = mListaTitularLayoutLocal.get(i);
TextView1 t2 = mListaTitularLayoutVisitante.get(i);
t1.setText(String.value(milis + mCurrentMilis1));
t2.setText(String.value(milis + mCurrentMilis2));
}
}
Am I doing anything wrong, or is it just that I'm trying to do something very complex in terms of efficiency?
#Sherif brings up a good point about hidden alpha values that bog down your application a lot.
Depending on your platform you may also want to check
<application android:hardwareAccelerated="true"... />
Another thing you can look into that may help performance is not firing off all those Intents. Once you start firing intents you are getting the system involved and depending on how they are getting resolved it may take some extra time.
For this issue I like to use Handlers. They are more light weight than intent.
You may also want to look at AsyncTask. This is basically like a thread, but also gives hooks that run on the UI Thread so you can perform both perform a background operation and update the UI without have to post runnables.
EDIT: Lastly, you can always run your layouts through the layoutopt tool. I was personally told by Romain Guy himself that if your drawing too slow, than you need to draw less. Just check out a screenshot (from a less than ideal view tree, but well within the max) from the profiling tool. You can see how much of the resources view drawing takes up. It's very important to keep this as lean as possible if you want your app to be responsive.
EDIT: It is no longer called layoutopt, it's called lint. Check your ~/android-sdk/tools/
I have once faced a situation where a fragment was really slow.
I am just predicting that your fragment has some kind of alpha and it is drawn on a 'heavy' activity.
The conclusion is that each time you are setting the text of a textview your whole view hierarchy is being invalidated.
It seems that fragments have this flaw. Anyway, use some layout instead of the fragment and check if it remains 'slow'.
ADDITION: A wrap_content textview will cause much more delay after a setText than a fill_parent textview.
You're likely running into slowdowns due to layout management with TableLayout and TextView. Every time you update text in one of those, a large amount of view measuring has to take place in order to put the characters in the right place on the screen. You should really just profile the app yourself using Traceview to find out. More information at: http://developer.android.com/tools/debugging/debugging-tracing.html
I've had the exact same issue you're seeing with the same type of layout (Fragment > TableLayout > Multiple TextViews). One way to test if your TableLayout/TextView setup is to blame is simply replace all that with a single TextView. That will probably run pretty well. Then put your 14 views into a FrameLayout or RelativeLayout. Even if they all overlap, you should still get decent performance, because it's the complexity of the TableLayout view measurements that's really causing slowdown.
As someone said you can use HardwareAccelerated but this is not a great solution, you will waste ram and cpu if you can't solve it in a different way. A solution probably more safety is to reduce the number of TextView. Try to reduce 14 to 7 and it will go twice faster. Usually is hard to do it but if you put the objects in a strategy position a pair of TextView one above other can be together if you make a TextView with two lines. And don't forget that findViewById is so expensive, if you will use a view object often find it one time and hold its reference.
Benchmarks are always useful for determining where slowness actually comes from, but I feel pretty confident suggesting that sending an Intent is probably much slower than updating 14 TextViews. Sending 10 Intents per second is a sign that you're Doing It Wrong (TM). This is just isn't what they're for.
Am I doing anything wrong, or is it just that I'm trying to do something very complex in terms of efficiency?
Updating 14 TextViews per second isn't inherently complex; you should be able to easily achieve this with a more appropriate application design. ASyncTask or Handler come to mind as possible tools, but it's hard to know what's best without knowing more about exactly what you're trying to do.
You can try to declare vars outside the loop :
public void actualizarTiempoJuego(long milis){
// Se recuperan los tiempos acumulados y se
// aumenta la cantidad pasada como parámetro
long mCurrentMilis1;
long mCurrentMilis2;
TextView1 t1;
TextView1 t2;
for(int i=0;i<7;++i) {
mCurrentMilis1 = mVectorMilis1.get(i);
mCurrentMilis2 = mVectorMilis2.get(i);
t1 = mListaTitularLayoutLocal.get(i);
t2 = mListaTitularLayoutVisitante.get(i);
t1.setText(String.value(milis + mCurrentMilis1));
t2.setText(String.value(milis + mCurrentMilis2));
}
}
And to setText() with mixed type, you can try setText("" + milis + mCurrentMilis2);
I would like to create dynamic table in android (custom number of rows and columns). Minimum sdk is 3.0
I suppose to crate it via one of 2 ways:
1) via creating new TextView
TableRow tr = ....;
for ( i = 0; i < NumOfRows .... ) {
TextView tv = new TextView(this);
tv.setLayoutParams(...);
tv.setText("Text I wanna to see");
tr.add(tv);
}
2) via inflater
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for ( i = 0; i < NumOfRows .... ) {
TextView tv = (TextView) mInflater.inflate(R.layout.my_cell_layout, null, false)
.findViewById(R.id.my_cell_item);
tv.setText("Text I wanna to see");
tr.add(tv);
}
3) Your way :)
What is faster? What should I select?enter code here
It's all as per your requirement that which is better.
from link http://www.aslingandastone.com/2010/dynamically-changing-android-views/
Because layouts can be created either in XML or in code, you could probably make do without ever having to do dynamic XML layout loading. That being said, there are some clear advantages as to why I think one may want to do so:
Code cleanliness. Doing anything more than basic layouts in code can get very messy, very fast.
Code re-use. It’s extremely easy to inflate an XML layout into a specified view with one or two lines of code
Performance. Creating the objects necessary for an in-code layout leads to unnecessary garbage collection. As per the Android Designing for Performance article, “avoid creating short-term temporary objects if you can.”
Attribute availability. Defining Views in an XML layout exposes attributes that are not always available by object methods.
*
Possible disadvantages:
It make take more time to do an XML layout versus defining the layout in code, especially if there are only one or two interface elements that need to be changed.
*
To find out which is faster, implement both methods and use the method profiling utility, TraceView. That being said, its easier to maintain an XML file when making changes than it is to modify code. So, if I were you, I would prefer technique #2.