Android - Good practices to avoid Memory leaks - android

Do you know good practices to avoid memory leaks ?
I am currently working on an app which has few memory leaks, that I struggle to fix, mainly because I don't know the habits that I need to take to be able to avoid them.
For instance, at the moment I get this issue
Fatal Exception: java.lang.OutOfMemoryError
Failed to allocate a 1627572 byte allocation with 1293760 free bytes and 1263KB until OOM
Raw Text
dalvik.system.VMRuntime.newNonMovableArray (VMRuntime.java)
android.view.LayoutInflater.inflate (LayoutInflater.java:429)
com.XX.Dialog.PopupDialog.onCreateView (PopupDialog.java:50)
Which comes from the inflater.inflate(R.layout.dialog_popup, container, false); in the onCreateView !
Here is the DialogFragment concerned :
public final class PopupDialog extends DialogFragment {
public PopupDialog()
{
}
#Override
public void onSaveInstanceState(Bundle outState) {
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
View view = inflater.inflate(R.layout.dialog_popup, container, false);
return view;
}
The layout is quite long, but basically it got 5 ImageViews . Here is an sample :
<ImageView
android:layout_width="match_parent"
android:layout_height="80dp"
android:id="#+id/popup_top_bg_iv"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="false"
android:layout_alignParentStart="false"
android:src="#drawable/popup_top_bg"
android:scaleType="fitXY"
android:background="#color/transparent" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/popup_top_bg_iv"
android:background="#ffffff"
android:layout_alignBottom="#+id/popup_bottom_ll" />
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/popup_top_iv"
android:src="#drawable/popup_0_top"
android:scaleType="fitCenter"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp" />
....
So .... I was wondering if you know :
1. What could lead to this memory leak error from this dialogFragment ?
2. Any good practices in android to avoid memory leaks ?
For instance for that file, should I call
imageView.setImageDrawable(null);
On every Imageview when the popup is closed / Activity is closed (R.drawable.* ) ? Or just when I load an image from an URL (with Glide for instance) dynamically ?
Should I always resize an image to the dimension of my Imageview ?
What exactly do I need to clean after the Fragment/Activity is closed ?
What do you think ?

After a bit of digging I came with these solutions :
you can use Leak canary to track your memory leak (https://github.com/square/leakcanary)
Or the Memory monitor of Android studio : https://developer.android.com/studio/profile/am-memory.html
Use a library to load your images such as Picasso or Glide. Personally I prefer Glide.
https://medium.com/#multidots/glide-vs-picasso-930eed42b81d
Never keep references of Activity of context in static. NEVER!
Otherwise your references might still be there even if you need it.
Avoid keeping references of ImageViews. Recycle / Clear the bitmap inside when your destroy the view.
If you need to have a reference of the context, please use context.getApplicationContext();
Don't use context.getApplicationContext(); for LayoutInflater.from(context); but directly the context.
(in case if you need to inflate a view or need a context for something).
If you use the context.getApplicationContext() it can lead to some design issues if you create views dynamically.
If you get some OutOfMemory error, think to compress your images ! It actually saves me lot of OutOfMemory error. You can use https://tinypng.com/.
Don't put by default your images into the folder drawable-xhdpi but drawable-mdpi instead as drawable-mdpi is the default one.
So for my issue I just need to compress the images and put them back in the drawable-mdpi folder ! All good now !

Related

Fresco : Display Wrong Image in listitems

I am using fersco library for loading local image. Initially i am displaying placeholder image in each item.Once the image is downloaded then i am storing that image in to local path and then load image via setImageUri function. If i am scrolling fast at the time of downloading image it display different image and re-appearing some time keep on changing if i am stop scrolling.
My SimpleDraweeView :
<com.facebook.drawee.view.SimpleDraweeView
android:id="#+id/fake_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center|center_horizontal|center_vertical"
android:adjustViewBounds="true"
android:contentDescription="#string/app_name"
android:scaleType="centerInside" />
My Adapter Code is :
GenericDraweeHierarchy hierarchy = setHierarchyForDraweeView(mImageView, 300);
hierarchy.setFailureImage(mContext.getResources().getDrawable(R.drawable.broken_image_black));
mSimpleDraweeView.setImageURI(Uri.fromFile(new File(mPath/local path/)));
SetHierarchyForDraweeView Function :
private GenericDraweeHierarchy setHierarchyForDraweeView(SimpleDraweeView draweeView, int duration) {
if (draweeView != null) {
if (draweeView.getHierarchy() == null) {
GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(mContext.getResources());
GenericDraweeHierarchy hierarchy = builder
.setFadeDuration(duration)
.setPlaceholderImage(new AsyncColorDrawable(mContext.getResources()))
.setFailureImage(mContext.getResources().getDrawable(R.drawable.broken_image_black))
.build();
draweeView.setHierarchy(hierarchy);
} else {
GenericDraweeHierarchy hierarchy = draweeView.getHierarchy();
hierarchy.setFadeDuration(duration);
return hierarchy;
}
}
return null;
}
AsyncColorDrawable Class :
private class AsyncColorDrawable extends ColorDrawable {
public AsyncColorDrawable(Resources res) {
super(res.getColor(R.color.RED));
}
}
I am doing anything wrong ?
I see several things that should be fixed, but none of which would explain incorrect loading. I will be able to help, but I'll need the logcat logs as explained here. Also, there is one thing I don't fully understand. From your description it seems that you are downloading your images manually, saving them to disk and when they are downloaded you set the Uri. Why not using Fresco to automatically download and disk-cache images for you? Can you provide this piece of code as well, because the issue might very well be there.
Things that should be fixed:
adjustViewBounds and scaleType attributtes are not supported by SimpleDraweeView. Drawee operates on several images at once (placeholder, failure image, actual image, etc.) Each can have its own scale type so you need to use Drawee atrributes as explained here.
If you are inflating your view from XML, draweeView.getHierarchy should never be null. You would have a NullPointerException anyway because you are not returning hierarchy from that if-branch. So, you can specify your failure image via XML too, no need to do that programmatically. Same for the fade duration if you always use the same value.

RecyclerView laggy scrolling

I am loading 400x200 images in RecyclerView, but scrolling is laggy on 2k devices. I am using Picasso for loading images from resource.
As you can see in the demo images are blurry on 2k screen, but if I load higher resolution images the situation gets worse.
How to fix this, I am not even loading large image, its 400x200 ?
Demo
Here is my code
card_view.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
card_view:cardPreventCornerOverlap="false"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
card_view:cardCornerRadius="2dp">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/rel">
<ImageView
android:id="#+id/cardimage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="#drawable/p7"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
android:paddingBottom="24dp"
android:textStyle="bold"
android:textSize="24sp"
android:id="#+id/cardtitle"
android:layout_gravity="center_vertical"/>
</LinearLayout>
</android.support.v7.widget.CardView>
Myadapter Code
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
private Context mContext;
List<Flower> list = new ArrayList<>();
public CardAdapter(Context mContext, List<Flower> list) {
this.mContext = mContext;
this.list = list;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_view, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.Flower=getItem(position);
holder.cardtitle.setText(list.get(position).name);
Picasso.with(mContext)
.load(list.get(position).id)
.placeholder(R.drawable.ic_launcher)
.into(holder.cardimage);
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public int getItemCount() {
return list.size();
}
public Flower getItem(int i) {
return list.get(i);
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView cardimage;
TextView cardtitle;
Flower Flower;
public ViewHolder(View itemView) {
super(itemView);
cardimage = (ImageView) itemView.findViewById(R.id.cardimage);
cardtitle = (TextView) itemView.findViewById(R.id.cardtitle);
}
}
}
UPDATE: I am loading images from resource, I am not downloading nothing
Here is my array
private void initializeData() {
flowers = new ArrayList<>();
flowers.add(new Flower("Flower 1", R.drawable.p8));
flowers.add(new Flower("Flower 2", R.drawable.p10));
flowers.add(new Flower("Flower 3", R.drawable.p11));
flowers.add(new Flower("Flower 4", R.drawable.p8));
flowers.add(new Flower("Flower 5", R.drawable.photo2));
flowers.add(new Flower("Flower 6", R.drawable.photo6));
flowers.add(new Flower("Flower 7", R.drawable.p12));
flowers.add(new Flower("Flower 8", R.drawable.p9));
flowers.add(new Flower("Flower 9", R.drawable.p8));
flowers.add(new Flower("Flower 10", R.drawable.p8));
flowers.add(new Flower("Flower 11", R.drawable.p8));
flowers.add(new Flower("Flower 12", R.drawable.p10));
}
UPDATE 2 : Guys I fixed most of the lag by setting adapter.setHasStableIds(true) , but app is still laggy on the first scroll while images are not loaded yet, how to fix that ?
UPDATE 3: I just tried loading images from web and everything seems smooth, probably there is some problem with loading images from resource .
Ok, thank you guys, I am gonna load my images from web.
if you are using two or more recycler views like (RecyclerView and NestedView)
try this
recyclerView.setNestedScrollingEnabled(false);
Source : Recyclerview inside Nested Scrollview scroll but does not fast scroll like normal Recyclerview or Nested Scrollview
Is RecyclerView.setHasFixedSize() set to true? I'm not able to reproduce this lag...can you please post the whole project on git? Check this out, maybe it can help you: http://antonioleiva.com/recyclerview/
I Believe that sometimes you may piss off when only trying some static images in drawable to display your recycler view. And it happens extremely lagging.
Why? You may not get this issue when using some library to load an image from url (Picasso, Glide, ...), but what happens with the same image, the same size, and it's right in your drawable (not need to download at all). And after a while, I figure out, android did some trick to resize an image in drawable for us to get a proper image in different resolution devices. So my suggestion is to use drawable-nodpi to store your image in order for android not to interfere with our images.
This is because the image is taking time to load.
Firstly, change your code for loading image as the below one...
Picasso.get().load(list.get(position).id).fit().centerCrop()
.placeholder(R.drawable.ic_launcher)
.into(holder.cardimage);
Then, before setting the adapter on recyclerview to the instance of CardAdapter inside MainActivity add this line..
yourAdapter_name.setHasStableIds(true);
One more tip...If anyone is using large drawables (xxxhdpi, xxhdpi ), first convert them into mdpi or ldpi . This will also improve the performance a lot and also reduces the apk size.You can use this website NativeScript Image Builder
This could be because of Picasso taking time to load the image. Use the below snapshot and adjust accordingly.
Picasso.with (context)
.load (url).fit().centerCrop()
.error (R.drawable.UserImage)
.into (imageView);
Use fit() and centerCrop() to avoid legginess.
You need to be getting the images asynchronously. As it is now, it stalls to actually download the image.
Leave the imageview blank when it's created, but have some sort of listener to set the image when it's been downloaded.
if you use Recyclerview in vertical mode and your activity contains other item that you have ScrollView then you must use NestedScrollView instead of ScrollView.
as described in google documentation NestedScrollView is just like ScrollView, but it supports acting as both a nested scrolling parent and child on both new and old versions of Android. Nested scrolling is enabled by default.
I had laggy recyclerView issue when one of the textView within the recyclerView was receiving null values. I fix this and my recyclerView stopped lagging.
It might be late, but maybe somebody will find it useful. Had the same problem, problem was at line:
Picasso.get().load(image).into(holder.imageView);
so I added fit().centerCrop() like this:
Picasso.get().load(image).fit().centerCrop().into(holder.imageView);
That solved my problem
I am bit late but this can be fixed bu using thumbnail with Glide.
Glide.with(context)
.load(URL)
.dontAnimate()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.thumbnail(0.5f)
.centerCrop()
.into(imageView);
In my case, bitmap creation was making delay for scroll. So I put bitmap creation in background thread and set to image in UI thread. This way, UI is not blocked for bitmap creation
new Thread(new Runnable() {
#Override
public void run() {
Bitmap myBitmap = BitmapFactory.decodeFile(filepath);
activity.runOnUiThread(new Runnable() {
public void run() {
vItem.imgProfile.setImageBitmap(myBitmap);
}
});
}
}).start();
from my experience with recyclerview what i found the possible cause could be is the image size.
beside that adding property ( setNestedScrollingEnabled(false); ) to the recyclerview and ( setHasStableIds) to the adapter does help to make recyclerview work smoothly.
So, bottom line is, if your recyclerview has image to load from network make sure to override their size or use thumbnail property(in glide).
this tricked saved my life and i hope it might save others life as well.
Happy coding :)
A bit late but I found leveraging Kotlin Coroutines as an effective way to make your onBindViewHolder() calls cheap, by offloading your image loading on to a background thread. I use Glide to load 384x384 images and the scrolling is smooth for upto a couple of thousand images.
// Here, defaultScope = CoroutineScope(Dispatchers.Default + SupervisiorJob())
// Key idea is to launch the Glide call on a background thread.
defaultScope.launch(exceptionHandler) {
Glide.with(view)
.load(uri)
.also {
// When Glide is done preparing the resource,
// use Main thread to load into ImageView.
withContext(Dispatchers.Main) {
it.into(view)
}
}
}
For Picasso, it will be a similar thing (though I haven't tried it personally), where into() must be invoked from the Main thread and the preparation on the background thread.
I think the reason is that Picasso caches your images but since you have a list of drawables that you bundle together with your app, you do not in theory need to cache your images. Caching is only useful when you are downloading the image from the internet and you don't want the app to redownload the images each time you swipe up or down on the recyclerview.
I would adjust the way picasso works by changing the memorypolicy so try this instead :
Picasso.with(getContext()).load(data.get(pos).getFeed_thumb_image()).memoryPolicy(MemoryPolicy.NO_CACHE).into(image);

Android: requestLayout() improperly called

The following error occurs when I attempt to inflate a layout within a ListView:
requestLayout() improperly called by android.widget.TextView{...} during layout: running second layout pass
I am attempting to inflate a layout within a ListView as follows:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) musicActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_item, parent, false);
...
}else{...}
}
The layout being inflated can look as simple as the following, and will still produce the error
<TextView
android:id="#+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="#dimen/txt_size"/>
I have looked into similar questions, and no solutions found seem to work Question 1, Question 2, Question 3.
Does anyone know what causes this type of error? Any troubleshooting advice? For more context, this ListView is displayed within a Fragment within a ViewPager
UPDATE
Here is the full XML Layout (minus a bunch of attributes), that still results in the problem
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/txt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txt2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txt3"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txt4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
Based on this, I would think the XML itself is not a problem, unless it has to do with the fact that I am using a ViewPager and Fragments
This issue seems to be a bug in the android implementation, please see: https://code.google.com/p/android/issues/detail?id=75516
Activating the fast scroll feature of a ListView in your code via ListView.setFastScrollEnabled(true) will trigger this bug and you'll start seeing the
requestLayout() improperly called by android.widget.TextView{...}
during layout: running second layout pass
message in your console.
This bug must have been introduced in one of the KitKat (4.4.x) updates, as I've not seen it with the initial KitKat (4.4.0) release. Apart from the ugly console spamming with the debug message from above, there seem to be no other impacts (maybe performance in some cases, which I haven't tested).
Cheers
PS: it's not the first time that the fast scroll feature is bugged, e.g. https://code.google.com/p/android/issues/detail?id=63545, 63545 was fixed in KitKat 4.4.3 but 75516 poped up thereafter --> seems to be a vexed subject for google ;-)
EDIT May 12 2015:
I updated my Nexus 7 to Android 5.1 some minutes ago (was Running 5.0 before) and stopped seeing this issue in this new version. As the appearance of the FastScroll indicator also changed in 5.1, I assume that google fixed this issue or at least commented out those ugly lines that spammed the console...
75516 & 82461 are still 'unresolved', but I guess that those refer to the same issue, that's now resolved in 5.1.
The problem is that while the method getView() of your adapter is displaying your layout some other code is trying to access this view to display it, resulting in a collision.
Note that some methods, that maybe you don't take care of (like setScale(), setTypeFace()) indeed call requestLayout(), so it would be interesting what you are doing after your inflate statement.
For me this issue was occurring upon a setLayoutParams() call. The solution was posting a runnable on the looper:
// java
imageView.post(new Runnable() {
#Override public void run() {
imageView.setLayoutParams(params);
}
});
// kotlin
post(Runnable { imageView.setLayoutParams(params) })
I fixed this issue by disabling fastScroll on the ListView in the XML.
<ListView
android:id="#+id/mListview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:fastScrollEnabled="false"
/>
In my case (Samsung Galaxy S4, API 21) this happened in ListView with EditTexts. I have a listener for field validation. Something like:
edit.setOnFocusChangeListener(new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
error.setVisibility(View.INVISIBLE);
error.setText("");
} else {
String s = edit.getText().toString();
if (s.isEmpty()) {
error.setText("Error 1");
} else if (s.length() < 2 || s.length() > 100) {
error.setText("Error 2");
}
error.setVisibility(View.VISIBLE);
}
}
});
After settinging focus in one of these EditTexts an above check is called. After that a TextView will change (the TextView contains an error message and lies over the EditText).
Setting focus to the second or the third EditText led to permanent request of the first EditText and return to current. An applications runs in infinite loop of requests (focus edittext 1, unfocus edittext 1, focus 3, unfocus 3, focus 1, etc).
I tried to set listView.setFastScrollEnabled(false). Also I tried a requestLayout() of some elements like in https://github.com/sephiroth74/HorizontalVariableListView/issues/93 with no chances.
Currently I made that TextView of fixed width and height in XML:
<TextView
android:id="#+id/error"
android:layout_width="match_parent" (or "200dp", but not "wrap_content")
android:layout_height="20dp"
.../>
After some experiments I noticed that a height of 20dp can be replaced with "wrap_content". But if a text is too long that divides into 2 lines, the application again catches in the infinite loop. So, android:singleLine="true" will help. It is deprecated, but amazingly android:maxLines="1" with android:lines="1" don't help as they again request layout.
Eventually we have:
<TextView
android:id="#+id/error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:textColor="#f00"
android:textSize="20sp"
tools:text="Error message"/>
That's not a good solution, but at least it breaks the infinite loop.
This might happen if you are using some 3rd party extension of ListView. Replace that with standard ListView and check if it still throws the error.
I had similar problem. Please check Android layout: running second layout pass and my answer.
I had the same issue with Kitkat 4.4.4 on Motorola X with Genymotion. In my case the list item is a simple CheckedTextView and the error occurred in AppCompatCheckedTextView.
As a normal implementation I inflated the item from XML layout file like below:
if (convertView == null) {
convertView = inflater.inflate(R.layout.checkable_list_entry, parent, false);
}
After some trying I found out that this has something to do with XML inflation. I don't know the root cause, but as a solution I decided to inflate the list item by code and set all the properties by code too.
It ended up like this:
CheckedTextView view;
if (convertView == null) {
view = new CheckedTextView(parent.getContext());
view.setMinHeight(getResources().getDimensionPixelSize(R.dimen.default_touch_height));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
view.setTextAppearance(R.style.SectionEntry);
} else {
view.setTextAppearance(parent.getContext(), R.style.SectionEntry);
}
view.setBackgroundResource(R.drawable.form_element);
view.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.WRAP_CONTENT));
} else {
view = (CheckedTextView) convertView;
}
I had a problem with the same warning log :
requestLayout() improperly called by android.support.v7.widget.AppCompatTextView {...} during layout: running second layout pass
I was working with recylcerview and going to update it with new data.
The only solution that worked for me is as below :
Step(1). Remove current data :
public void removeAll() {
items.clear(); //clear list
notifyDataSetChanged();
}
Step(2). When you want to populate the recyclerview with new data, first set a new LayoutManager to recyclerview again:
private void initRecycleView() {
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false));
}
Step(3). Update the recyclerview with new data. for example :
public void refreshData(List newItems) {
this.items = newItems;
notifyItemRangeChanged(0, items.size());
}
Try taking off the textSize from the xml and setting it in Java code. I think that's causing it to be laid out twice.
In my case this warning prevented a button from showing up in API 21 devices. The button visibility was previously set to GONE.
The only workaround I got it was setting to INVISIBLE instead of GONE for API 21. It wasn't a real solution but it was acceptable for me.
I only post this because it can be useful from somebody.
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
theButton.setVisibility(View.INVISIBLE);
}
else {
theButton.setVisibility(View.GONE);
}
Sometimes you maybe already fixed the issue but it still keeps same error, so you need to close visual studio then delete all bin and obj folders from your projects, then uninstall the app from the emulator. then walah!! everything will works fine
I solved the problem like this:
mHolder.txt_fword.setTextSize(22);
mHolder.txt_farth.setTextSize(22);
mHolder.txt_fdef.setTextSize(22);
mHolder.txt_fdef2.setTextSize(22);
mHolder.txt_frem.setTextSize(22);
//if (fdef2.get(pos).equals("")) mHolder.txt_fdef2.setVisibility(View.GONE);
//if (frem.get(pos).equals("")) mHolder.txt_frem.setVisibility(View.GONE);
issue is .setVisibility(View.GONE); , change to .setVisibility(View.VISIBLE);

show progress icon while loading page in ViewPager

I am using AsyncTask in my application to load data from Internet. Here is onPostExecute method of my class that extends Async class.
protected void onPostExecute(Article result) {
super.onPostExecute(result);
TextView txtTitle= (TextView) view.findViewById(R.id.title);
txtTitle.setText(result.getTitle());
TextView txtMain= (TextView) view.findViewById(R.id.main);
txtMain.setText(result.getContent());
}
This is the overridden method from PageAdapter that instantiate pages. customlayout is the layout that shows article.
public Object instantiateItem(View container, int position) {
LayoutInflater inflater = (LayoutInflater) container.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View page= inflater.inflate(R.layout.customlayout , null);
Worker aw = new Worker(page, container.getContext());
aw.execute(links.get(position));
((ViewPager) container).addView(page,0);
return page;
}
Here is layout of a page that is inflated in each page.
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="#+id/main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp" />
What I am trying to achieve is show a progress information until data loads. I should be able to swipe through page even while loading.
I would be grateful if anyone would help.
Also how can I control number of pages that are being loaded in background?
If you are looking for a spinning progress bar, you can try this:
xml:
<FrameLayout android:id="#+id/progressContainer">
<ProgressBar style="#android:style/Widget.ProgressBar.Large"
android:layout_gravity="center" />
</FrameLayout>
activity:
private View progressContainer;
#Override
public View onCreateView(...) {
progressContainer = v.findeViewById(R.id.progressContainer);
progressContainer.setVisibility(View.INVISIBLE);
}
So whenever you need to display the Progress just set the View to visible.
If you want to be able to still interact with your activity, you can just modify the clickability of the parent FrameLayout:
android:clickable="true" (or "false")
Set it to false if you want to interact, and true to block!
I recommend to use fragments as your viewPager items, and implement the loading pattern inside the fragment i.e - https://github.com/johnkil/Android-ProgressFragment
Regarding number of pages being loaded see - setOffscreenPageLimit
If I am not wrong. You are creating something like youtube video, fetching the frame on background and keep update it. In your case is book, fetching pages on background and keep update on it.
First, What you needs is fragment as you cannot destroy your AsyncTask that running on your activity.
Second, AsyncTask publishProgress and onProgressUpdate(Progress...) method, it help you to report background condition. You can take a look at the usage example provided by android
http://developer.android.com/reference/android/os/AsyncTask.html

Memory leak for Android Google Maps API v2

I'm struggling with a memory leak issue at Google Maps Android API v2. The heap usage increases by about 85KB every time my view becomes visible again after:
Phone screen turns off (eg after pressing the power button).
The user exits the app pressing the Home button.
The app eventually crashes with an OutOfMemory exception. The leak does NOT occur on screen rotate, or when exiting by "back" button. Any ideas about a workaround or the reason behind this problem?
My code:
public class LeakActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leak);
}
}
and the XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/map_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</RelativeLayout>
This might be related to this open issue in the Maps API:
Issue 4766 - Bug: Android Maps API v2 leaks huge amounts of memory
Use DDMS' "Dump HPROF" tool to dump a hprof file, convert it with hprof-conv and use MAT to examine the leak. If it's in Google Maps API, please post an apk (or better simple test code) to the open issue and include the hprof file.
If it is the same bug I am experiencing, it might only happen on Android 2.x, please check that too.
I tried to use System.gc() and map.clear() before the map is initialized.
#Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()) == ConnectionResult.SUCCESS) {
System.gc();
getMap().clear();
setupmap();
}
}
#Override
public void onLowMemory() {
super.onLowMemory();
System.gc();
}

Categories

Resources