Search code examples
androidperformanceviewgifanimated-gif

Best practice of showing gif in Android


I tried to load a list of gifs and displays them on listview. Currently, I display each gif into a webview but it's very slow and looks ugly. I did some researches today but nothing could help me.

Do you guys have any great idea that showing gifs smoothly? BTW, I got all gifs from url links.


Solution

  • I would recommend utilising a recently open sourced library, released by Facebook, called fresco https://github.com/facebook/fresco. From my experience, it handles GIFs quite nicely by using some fancy caching methods outside of VM heap to avoid staggering effects of GC on bitmaps/images. User guide: http://frescolib.org/docs/getting-started.html#_

    Below is just a basic adapter to implement into a listview:

    public class FrescoGifAdapter extends BaseAdapter {
    
    
        ArrayList<String> urlList;
        private static LayoutInflater inflater=null;
    
        public FrescoGifAdapter(Activity activity, ArrayList<String> urlList) {
    
            if(urlList==null) {
                this.urlList = new ArrayList<>();
            }
            else {
                this.urlList = urlList;
            }
            inflater = (LayoutInflater)activity.
                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    
        }
    
        public int getCount() {
            return urlList.size();
        }
    
        public String getItem(int position) {
            return urlList.get(position);
        }
    
        public long getItemId(int position) {
            return position;
        }
    
        public View getView(int position, View convertView, ViewGroup parent) {
    
            View vi = convertView;
    
            if(convertView==null){
                vi = inflater.inflate(R.layout.fresco_item, null);
                //Load Uri with URL.
                Uri uri = Uri.parse(getItem(position));
    
                SimpleDraweeView draweeView = (SimpleDraweeView) vi.findViewById(R.id.my_image_view);
    
                //Controller is required for controller the GIF animation, here I have just set it to autoplay as per the fresco guide.
                DraweeController controller = Fresco.newDraweeControllerBuilder()
                        .setUri(uri)
                        .setAutoPlayAnimations(true)
                        .build();
                //Set the DraweeView controller, and you should be good to go.
                draweeView.setController(controller);
    
            }
    
            return vi;
        }
    
    }
    

    fresco_item.xml (You can change dimensions to suit, I just defaulted to guide dimensions). Caveat is scaling has to be handled by fresco. In fact, they advise against setting any custom ImageView attributes as it breaks stuff.

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:fresco="http://schemas.android.com/apk/res-auto"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/my_image_view"
            android:layout_width="130dp"
            android:layout_height="130dp"
            fresco:placeholderImage="@drawable/ic_launcher"
            />
    
    
    </LinearLayout>
    

    And then in your onCreate:

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //Required by Fresco to be initalized before setContentView.
            Fresco.initialize(this);
            setContentView(R.layout.activity_main);
            ListView lv = (ListView) findViewById(R.id.listview);
            ArrayList<String> urlList = new ArrayList<>();
            //Load neon cats
            for(int i = 0; i < 10; i++) {
                urlList.add("https://media3.giphy.com/media/JLQUx1mbgv2hO/200.gif");
            }
    
            lv.setAdapter(new FrescoGifAdapter(this, urlList));
    
        }