how to avoid memory leaks in android - android

I am dynamically updating the tablelayout as shown below where I am appending an imagebutton and a Textview for each tableRow.Whenever I launch my activity it shows only 4 rows (should display 10 actually) but if I keep break points in code and debug slowly to figure out the problem it displays all the 10 rows properly. I doubt it must be a memory problem in the code as I am getting Images from the web which I feel takes lot of memory. I tried releasing views memory after adding to the layout but it is crashing all the time.
Please let me know where I am doing wrong.
for (int i = 0; i < parsedExampleDataSet.getAppNameString().size(); i++)
{
TableRow row = new TableRow(this);
TextView tv = new TextView(this);
tv.setText("AppName: "+ parsedExampleDataSet.getAppNameString().get(i) +"\n" + "Description: " + parsedExampleDataSet.getDescriptionString().get(i));
ImageButton imgBtn = new ImageButton(this);
URL aURL = new URL(parsedExampleDataSet.getImageUrlString().get(i));
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
Bitmap bm = BitmapFactory.decodeStream(bis);
imgBtn.setImageBitmap(bm);
imgBtn.setBackgroundColor(color.transparent);
imgBtn.setTag(parsedExampleDataSet.getMarketLinkString().get(i));
bis.close();
is.close();
row.addView(imgBtn);
row.addView(tv);
table.addView(row,new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); //here table is a tablelayout object
}
Thanks in advance
Prathima

If you want to load more than one row than use ListView.
It handles all memory issues and better than TableLayout.
here is one good example.

The answer seems to be located in parsedExampleDataSet.getAppNameString().size():
When you are running the program, the for(;;) loop iterates only 4 times
When you are running the debugger and stepping manually, it iterates 10 times, which is according to your expectation
How is populated parsedExampleDataSet.getAppNameString()? Its size is used as the upper bound of the for(;;) loop, and it seems to change over the time. Should it be populated by an asynchronous process (a thread) this would explain the issue.
Feel free to add more details and let me know. I'll edit/elaborate this answer further to the new elements you'll bring.

Related

Recursive function and comment trees

I am using the reddit API and trying to load the comment tree of a thread. My problem is that I am using a recursive function to do that. I am building a view and then adding it programmatically. And it works for small threads but when it has to load a large comment tree I get stackoverflow.So my main question is: what is a good way to load nested comments programmatically and what is the best practice to go around the stack overflow? I have debated adding a counter for comments added and when they exceed some number I might break the loop, but that still doesn't guarantee me a "stackoverflow" free program. Generally speaking how can I keep track of the stack and the heap? Also as a follow up question: my dynamic view gets destroyed on rotation and I recreate it every time. The problem with that is recreating is slow and it slows the rotation. So is there an easy way to keep/save the view on rotation and add it again (setRetainInstance(true) has no effect on the dynamic view, just on the main layout).
private void addTextTree(JSONObject j, LinearLayout layoutparent) throws JSONException {
JSONObject j2 = j.getJSONObject("data");
JSONArray j3 = j2.getJSONArray("children");
LinearLayout currentparent = layoutparent;
Log.d("ADDINGVIEW", j3.length() + "");
for (int i = 0; i < j3.length(); i++) {
JSONObject j4 = j3.getJSONObject(i);
JSONObject j5 = j4.getJSONObject("data");
addComment(j5, currentparent);
}
}
private void addComment(JSONObject j, LinearLayout parent) throws JSONException {
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
LinearLayout LLHmain = new LinearLayout(getActivity());
LinearLayout LLVsecond = new LinearLayout(getActivity());
LLHmain.setOrientation(LinearLayout.HORIZONTAL);
LLHmain.setLayoutParams(lp);
LLVsecond.setOrientation(LinearLayout.VERTICAL);
LLVsecond.setLayoutParams(lp1);
TextView author = new TextView(getActivity());
TextView content = new TextView(getActivity());
ImageView bar = new ImageView(getActivity());
bar.setBackgroundResource(R.drawable.lines);
LLHmain.addView(bar, lp1);
author.setText(" " + j.optString("author") + " " + j.optInt("score") + " points");
author.setBackgroundResource(R.drawable.border);
String temp = j.optString("body_html");
String temp1 = Html.fromHtml(temp.substring(22, temp.length() - 12)).toString();
content.setText(Html.fromHtml(temp1));
content.setAutoLinkMask(Linkify.WEB_URLS);
content.setMovementMethod(LinkMovementMethod.getInstance());
LLVsecond.addView(author, lp);
LLVsecond.addView(content, lp);
LLHmain.addView(LLVsecond, lp1);
parent.addView(LLHmain, lp);
if (!j.optString("replies").equals("")) {
JSONObject replies = j.getJSONObject("replies");
addTextTree(replies, LLVsecond);
}
}
Summed up:
What is the best way to handle loading trees of textviews and preventing stack overflow.
Keeping track of the stack and the heap
Saving dynamic view on rotation
Disclaimer: I am new to any sort of programming and by no means do I believe this is the best or only way to do it. I am open to any possible solutions regarding my problem.
I'll give the very short version of the answer (because I'm kinda busy at work) but you follow it that you'll get what you want:
The issue is that View are memory heavy objects and shouldn't be allocating that many. What you do to avoid that is using a ListView that can recycle views.
So instead of recursively create and add views you'll create a data class, for example:
public class DataItem{
String author;
String content;
}
then you build an ArrayList<DataItem> and recursively add all the items to this array. Then you use this array in an adapter in the listview.
that way you can have a thread with thousands of items without issue.

Displaying Images(numbers) to screen

I am working on a project that will display math problems to the screen such as:
10 + 5 =
and then the user will need to guess the answer. I am doing this as more of way for me to learn how android ticks.
I have images from 0 to 9 saved in the drawable folder for each of the dpi setting I need to account. I also have the operators (+,-,*,/,=) also saved.
My questions:
How easy is this to do?
How would I go about doing the above dynamically?
Thanks
--EDIT--
The images and operators are stored as .9.png files in my drawable folder. I have string-array contain my problems that I will randomly pull from and then display them to the screen.
In the past I would do the following:
public View buildProblem()
{
LinearLayout rtnView = new LinearLayout(ctx);
rtnView.setOrientation(LinearLayout.HORIZONTAL);
rtnView.setLayoutParams(new GridLayout.LayoutParams());
// Build LeftSide
Iterator<Integer> itor = buildLeftSide();
ImageView iv;
// loop through of iterator
while(itor.hasNext())
{
iv = new ImageView(ctx);
iv.setScaleType(ImageView.ScaleType.FIT_CENTER);
iv.setImageResource(itor.next());
itor.remove();
rtnView.addView(iv);
}
// Space
rtnView.addView(space);
// Operator
rtnView.addView(plusSign);
// Build LeftSide
itor = buildRightSide();
// another loop
while(itor.hasNext())
{
iv = new ImageView(ctx);
iv.setScaleType(ImageView.ScaleType.FIT_CENTER);
iv.setImageResource(itor.next());
itor.remove();
rtnView.addView(iv);
}
// Space
rtnView.addView(space);
// Equal Sign
rtnView.addView(equalSign);
// Space
rtnView.addView(space);
// return the view
return rtnView;
}
I was thinking of using ImageViews for the numbers to be displayed to the screen which I have used in the past but not sure if that is the best way to do it.
https://github.com/barakisbrown/MathTest -- Is one attempt at doing the above but I have now started to rewrite it from scratch so which is why I am asking for help.

Loading dynamic imageviews in loop in Android creating gaps

I am reading data from a SOAP service and then using that data to load images from the res folder locally. I am using a loop because there will always be six images being loaded. This is my code :
final TableLayout tblLay = (TableLayout)findViewById(R.id.lottotl);
final LayoutParams params = new TableLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
for(int i=2;i<9;i++) {
final ImageView image = new ImageView(LastDraw.this);
image.setLayoutParams(trparams);
image.setMaxHeight(20);
image.setMaxWidth(20);
String imgName = "img_" + split[i].substring(split[i].indexOf("=") + 1);
int id = getResources().getIdentifier(imgName, "drawable", getPackageName());
image.setImageResource(id);
row2.setLayoutParams(params);
row2.addView(image);
}
tblLay.addView(row2);
The issue I am having is that there is a gap between the first image and the consecutive images.
It looks like this (each number representing an image):
1.........23456
I am thinking it has to do with the layout of the row in the tablelayout, I could be wrong.
Thank you
Anyone?
Figured it out ... feel kind of stupid but, I learnt something! I load a textview into the first row and then the imageviews into the second row. The textview is in the first column and its width is making the first column stretch ... THAT is why there is a gap.

How to assign values from an array to textviews in android

I have 4 textview such as t11,t12,t13,t14 and I have also 4 value in array val[4].
I want to store these values randomly in textviews. but I am getting little problem.
I have done following code:
TextView t11,t12,t13,t14;
Random r = new Random();
for (int i = 0; i < val.length; i++) {
int val[4]=r.nextInt(10);
Log.d("horror", "Randm Array of VAL:" +val[i]);
}
In the Log,there are 4 values displayed but how to display them in textviews.
I have coded but it does not work properly.
t1[i+1].setText("" +val[i]);
and
In this case,values are properly displayed, but i want to do code optimization.
t11.setText("" +val[0]);
t12.setText("" +val[1]);
t13.setText("" +val[2]);
t14.setText("" +val[3]);
Thanks in advance.
Every time you loop in for, you create another integer array. Take the definition of val out of the for loop.
you can store their references inside an array , it won't create new objects. so this should do the job
TextView [] textviews = {t11,t12,t13,t14};
for(int i =0;i<textviews.length;++i){
textviews[i].setText(val[i]);
}
For your TextView use something like,
TextView [] tv = {t11,t12,t13,t14};
and use tv for other going stuff... So now, you can getting it work by,
tv[i+1].setText("" +val[i]);

Android fill array with ImageViews

I want an array of imageviews, but I don't know how to fill it with an object of type imageview.
ImageView[] forAdapter = new ImageView[imageIds.size()];
for(int i = 0; i < imageIds.size(); i++)
{
ImageView mImageView = new ImageView(context);
forAdapter[i] = mImageView.setImageDrawable(((imagesPulled.get(imageIds.get(i)))));
}
this doesn't work because .setImageDrawable does not return an imageview, and I dont know of any object that actually does!
I considered using drawables in an array, but I'm ultimately setting an arrayadapter for a listview, and I cant make a R.layout with drawables (I'll get a class cast exception because the xml file is using an ImageView not drawable type),so I only have ImageViews to put into an array - unless I'm approaching the problem wrong.
Your code is almost there! I'm just gonna make a small change and comment on it below:
ImageView[] forAdapter = new ImageView[imageIds.size()];
for(int i = 0; i < imageIds.size(); i++)
{
forAdapter[i] = new ImageView(context);
forAdapter[i].setImageDrawable(imagesPulled.get(imageIds.get(i)));
}
First: If you want to initialize forAdapter[i], you don't need to create a new variable and assign it to it. Just do it there:
forAdapter[i] = new ImageView(context);
Setting the image (using setImageDrawable, setImageResource, etc) doesn't return anything. It's an operation you do on the image itself so all you gotta do is call the method from the variable you want to modify:
forAdapter[i].setImageDrawable(imagesPulled.get(imageIds.get(i)));
You're done :)
If you have any doubts just ask in the comments.
Hope it helps.
Your mImageView is ImageView itself.
So, forAdapter[i] = mImageView should work fine. If you use additional actions, you can do them before assignment.

Categories

Resources