亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

【Android Developers Training】 60. 在你的UI

系統 1814 0

注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術一般,由于喜愛安卓而產生了翻譯的念頭,純屬個人興趣愛好。

原文鏈接: http://developer.android.com/training/displaying-bitmaps/display-bitmap.html


這節課程將結合之前所有課程所學習的知識,向你展示如何使用后臺線程和位圖緩存,在 ViewPager GridView 中展示多幅圖片,并解決并發和配置變更的問題。


一). 實現向一個ViewPager加載位圖

該滑動視圖模式( swipe view pattern )用來作為圖庫的閱覽室再好不過的了。你可以通過 PagerAdapter 來支持 ViewPager 實現這個閱覽模式。然而, 一個更合適的支持適配器是其子類 FragmentStatePagerAdapter ,它自動銷毀 ViewPager 中的 Fragments ,并保存其狀態(當它從屏幕消失時),從而保持內存使用不會太高。

Note:

如果你有更小數量的圖片,并確信他們能滿足應用的內存限制,那么使用平常的 PagerAdapter FragmentPagerAdapter 會更合適一些。

下面是一個具有 ImageView ViewPager 實現。主activity持有 ViewPager 和它的適配器:

      
        public
      
      
        class
      
       ImageDetailActivity 
      
        extends
      
      
         FragmentActivity {

    
      
      
        public
      
      
        static
      
      
        final
      
       String EXTRA_IMAGE = "extra_image"
      
        ;



    
      
      
        private
      
      
         ImagePagerAdapter mAdapter;

    
      
      
        private
      
      
         ViewPager mPager;



    
      
      
        //
      
      
         A static dataset to back the ViewPager adapter
      
      
        public
      
      
        final
      
      
        static
      
       Integer[] imageResIds = 
      
        new
      
      
         Integer[] {

            R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,

            R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,

            R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};



    @Override

    
      
      
        public
      
      
        void
      
      
         onCreate(Bundle savedInstanceState) {

        
      
      
        super
      
      
        .onCreate(savedInstanceState);

        setContentView(R.layout.image_detail_pager); 
      
      
        //
      
      
         Contains just a ViewPager
      
      
        

        mAdapter 
      
      = 
      
        new
      
      
         ImagePagerAdapter(getSupportFragmentManager(), imageResIds.length);

        mPager 
      
      =
      
         (ViewPager) findViewById(R.id.pager);

        mPager.setAdapter(mAdapter);

    }



    
      
      
        public
      
      
        static
      
      
        class
      
       ImagePagerAdapter 
      
        extends
      
      
         FragmentStatePagerAdapter {

        
      
      
        private
      
      
        final
      
      
        int
      
      
         mSize;



        
      
      
        public
      
       ImagePagerAdapter(FragmentManager fm, 
      
        int
      
      
         size) {

            
      
      
        super
      
      
        (fm);

            mSize 
      
      =
      
         size;

        }



        @Override

        
      
      
        public
      
      
        int
      
      
         getCount() {

            
      
      
        return
      
      
         mSize;

        }



        @Override

        
      
      
        public
      
       Fragment getItem(
      
        int
      
      
         position) {

            
      
      
        return
      
      
         ImageDetailFragment.newInstance(position);

        }

    }

}
      
    

之后是詳細 Fragment 的實現,它持有子 ImageView 。這看起來像是一個完美的實現,但是從中你能看出缺陷來嗎?有什么辦法可以改進它?

      
        public
      
      
        class
      
       ImageDetailFragment 
      
        extends
      
      
         Fragment {

    
      
      
        private
      
      
        static
      
      
        final
      
       String IMAGE_DATA_EXTRA = "resId"
      
        ;

    
      
      
        private
      
      
        int
      
      
         mImageNum;

    
      
      
        private
      
      
         ImageView mImageView;



    
      
      
        static
      
       ImageDetailFragment newInstance(
      
        int
      
      
         imageNum) {

        
      
      
        final
      
       ImageDetailFragment f = 
      
        new
      
      
         ImageDetailFragment();

        
      
      
        final
      
       Bundle args = 
      
        new
      
      
         Bundle();

        args.putInt(IMAGE_DATA_EXTRA, imageNum);

        f.setArguments(args);

        
      
      
        return
      
      
         f;

    }



    
      
      
        //
      
      
         Empty constructor, required as per Fragment docs
      
      
        public
      
      
         ImageDetailFragment() {}



    @Override

    
      
      
        public
      
      
        void
      
      
         onCreate(Bundle savedInstanceState) {

        
      
      
        super
      
      
        .onCreate(savedInstanceState);

        mImageNum 
      
      = getArguments() != 
      
        null
      
       ? getArguments().getInt(IMAGE_DATA_EXTRA) : -1
      
        ;

    }



    @Override

    
      
      
        public
      
      
         View onCreateView(LayoutInflater inflater, ViewGroup container,

            Bundle savedInstanceState) {

        
      
      
        //
      
      
         image_detail_fragment.xml contains just an ImageView
      
      
        final
      
       View v = inflater.inflate(R.layout.image_detail_fragment, container, 
      
        false
      
      
        );

        mImageView 
      
      =
      
         (ImageView) v.findViewById(R.id.imageView);

        
      
      
        return
      
      
         v;

    }



    @Override

    
      
      
        public
      
      
        void
      
      
         onActivityCreated(Bundle savedInstanceState) {

        
      
      
        super
      
      
        .onActivityCreated(savedInstanceState);

        
      
      
        final
      
      
        int
      
       resId =
      
         ImageDetailActivity.imageResIds[mImageNum];

        mImageView.setImageResource(resId); 
      
      
        //
      
      
         Load image into ImageView
      
      
            }

}
      
    

很好,你發現了問題所在:圖片時在UI線程上進行讀取的,因此可能會導致應用停止響應從而崩潰。使用一個在 Processing Bitmaps Off the UI Thread (博客鏈接: http://www.cnblogs.com/jdneo/p/3521195.html 中說的 AsyncTask ,它直接將圖片加載和處理移動到后臺線程中:

      
        public
      
      
        class
      
       ImageDetailActivity 
      
        extends
      
      
         FragmentActivity {

    ...



    
      
      
        public
      
      
        void
      
       loadBitmap(
      
        int
      
      
         resId, ImageView imageView) {

        mImageView.setImageResource(R.drawable.image_placeholder);

        BitmapWorkerTask task 
      
      = 
      
        new
      
      
         BitmapWorkerTask(mImageView);

        task.execute(resId);

    }



    ... 
      
      
        //
      
      
         include BitmapWorkerTask class
      
      
        }




      
      
        public
      
      
        class
      
       ImageDetailFragment 
      
        extends
      
      
         Fragment {

    ...



    @Override

    
      
      
        public
      
      
        void
      
      
         onActivityCreated(Bundle savedInstanceState) {

        
      
      
        super
      
      
        .onActivityCreated(savedInstanceState);

        
      
      
        if
      
       (ImageDetailActivity.
      
        class
      
      
        .isInstance(getActivity())) {

            
      
      
        final
      
      
        int
      
       resId =
      
         ImageDetailActivity.imageResIds[mImageNum];

            
      
      
        //
      
      
         Call out to ImageDetailActivity to load the bitmap in a background thread
      
      
                    ((ImageDetailActivity) getActivity()).loadBitmap(resId, mImageView);

        }

    }

}
      
    

任何額外的處理(比如改變尺寸或者從網絡獲取圖片)可以在 BitmapWorkerTask 中發生而不會影響到主 UI 的響應性。如果后臺線程所做的不僅僅是直接從磁盤讀取圖片,那么添加一個內存緩存或磁盤緩存也是有益處的(博客鏈接: http://www.cnblogs.com/jdneo/p/3522538.html )。下面是內存緩存的修改代碼:

      
        public
      
      
        class
      
       ImageDetailActivity 
      
        extends
      
      
         FragmentActivity {

    ...

    
      
      
        private
      
       LruCache<String, Bitmap>
      
         mMemoryCache;



    @Override

    
      
      
        public
      
      
        void
      
      
         onCreate(Bundle savedInstanceState) {

        ...

        
      
      
        //
      
      
         initialize LruCache as per Use a Memory Cache section
      
      
            }



    
      
      
        public
      
      
        void
      
       loadBitmap(
      
        int
      
      
         resId, ImageView imageView) {

        
      
      
        final
      
       String imageKey =
      
         String.valueOf(resId);



        
      
      
        final
      
       Bitmap bitmap =
      
         mMemoryCache.get(imageKey);

        
      
      
        if
      
       (bitmap != 
      
        null
      
      
        ) {

            mImageView.setImageBitmap(bitmap);

        } 
      
      
        else
      
      
         {

            mImageView.setImageResource(R.drawable.image_placeholder);

            BitmapWorkerTask task 
      
      = 
      
        new
      
      
         BitmapWorkerTask(mImageView);

            task.execute(resId);

        }

    }



    ... 
      
      
        //
      
      
         include updated BitmapWorkerTask from Use a Memory Cache section
      
      

}
    

將所有代碼片段放在一起,組成了響應良好的 ViewPager 實現,它有很小的圖片加載延遲,并且有能力在后臺根據你的需要處理圖片。


二).?實現向一個GridView加載位圖

grid list building block 對于展示圖片數據集是很有用的,并且可以通過一個 GridView 組件來實現。 GridView 組件允許同一時間在屏幕上顯示許多圖片,同時還有很多備用圖片(當用戶上下滑動頁面時,備用圖片將會被顯示)。當實現這個控制類型時,你必須保證UI的流暢性,內存使用可控,并發處理正確(根據 GridView 回收它的子View)。

我們首先來看一下一個標準的 GridView 實現,它有一個置于 Fragment 中的子 ImageView 。還是像之前一樣,請讀者思考這一看上去完美的實現是否有進一步提升的空間?

      
        public
      
      
        class
      
       ImageGridFragment 
      
        extends
      
       Fragment 
      
        implements
      
      
         AdapterView.OnItemClickListener {

    
      
      
        private
      
      
         ImageAdapter mAdapter;



    
      
      
        //
      
      
         A static dataset to back the GridView adapter
      
      
        public
      
      
        final
      
      
        static
      
       Integer[] imageResIds = 
      
        new
      
      
         Integer[] {

            R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,

            R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,

            R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};



    
      
      
        //
      
      
         Empty constructor as per Fragment docs
      
      
        public
      
      
         ImageGridFragment() {}



    @Override

    
      
      
        public
      
      
        void
      
      
         onCreate(Bundle savedInstanceState) {

        
      
      
        super
      
      
        .onCreate(savedInstanceState);

        mAdapter 
      
      = 
      
        new
      
      
         ImageAdapter(getActivity());

    }



    @Override

    
      
      
        public
      
      
         View onCreateView(

            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        
      
      
        final
      
       View v = inflater.inflate(R.layout.image_grid_fragment, container, 
      
        false
      
      
        );

        
      
      
        final
      
       GridView mGridView =
      
         (GridView) v.findViewById(R.id.gridView);

        mGridView.setAdapter(mAdapter);

        mGridView.setOnItemClickListener(
      
      
        this
      
      
        );

        
      
      
        return
      
      
         v;

    }



    @Override

    
      
      
        public
      
      
        void
      
       onItemClick(AdapterView<?> parent, View v, 
      
        int
      
       position, 
      
        long
      
      
         id) {

        
      
      
        final
      
       Intent i = 
      
        new
      
       Intent(getActivity(), ImageDetailActivity.
      
        class
      
      
        );

        i.putExtra(ImageDetailActivity.EXTRA_IMAGE, position);

        startActivity(i);

    }



    
      
      
        private
      
      
        class
      
       ImageAdapter 
      
        extends
      
      
         BaseAdapter {

        
      
      
        private
      
      
        final
      
      
         Context mContext;



        
      
      
        public
      
      
         ImageAdapter(Context context) {

            
      
      
        super
      
      
        ();

            mContext 
      
      =
      
         context;

        }



        @Override

        
      
      
        public
      
      
        int
      
      
         getCount() {

            
      
      
        return
      
      
         imageResIds.length;

        }



        @Override

        
      
      
        public
      
       Object getItem(
      
        int
      
      
         position) {

            
      
      
        return
      
      
         imageResIds[position];

        }



        @Override

        
      
      
        public
      
      
        long
      
       getItemId(
      
        int
      
      
         position) {

            
      
      
        return
      
      
         position;

        }



        @Override

        
      
      
        public
      
       View getView(
      
        int
      
      
         position, View convertView, ViewGroup container) {

            ImageView imageView;

            
      
      
        if
      
       (convertView == 
      
        null
      
      ) { 
      
        //
      
      
         if it's not recycled, initialize some attributes
      
      

                imageView = 
      
        new
      
      
         ImageView(mContext);

                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);

                imageView.setLayoutParams(
      
      
        new
      
      
         GridView.LayoutParams(

                        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

            } 
      
      
        else
      
      
         {

                imageView 
      
      =
      
         (ImageView) convertView;

            }

            imageView.setImageResource(imageResIds[position]); 
      
      
        //
      
      
         Load image into ImageView
      
      
        return
      
      
         imageView;

        }

    }

}
      
    

再一次地,這個實現的問題在于圖片設置是在UI線程中執行的。雖然這樣做對于簡單,尺寸小的圖片來說沒有問題(當然還和系統加載和緩存的資源有關),如果還有其他額外的處理要做,那么你的UI會戛然而止。

之前章節的異步處理和緩存的方法可以在這里實現。然而,你也需要警惕并發的問題,因為 GridView 會回收它的子View。要處理這個問題,使用在 Processing Bitmaps Off the UI Thread 課程(博客鏈接: http://www.cnblogs.com/jdneo/p/3521195.html )中所講的知識。下面是升級后的解決方案:

      
        public
      
      
        class
      
       ImageGridFragment 
      
        extends
      
       Fragment 
      
        implements
      
      
         AdapterView.OnItemClickListener {

    ...



    
      
      
        private
      
      
        class
      
       ImageAdapter 
      
        extends
      
      
         BaseAdapter {

        ...



        @Override

        
      
      
        public
      
       View getView(
      
        int
      
      
         position, View convertView, ViewGroup container) {

            ...

            loadBitmap(imageResIds[position], imageView)

            
      
      
        return
      
      
         imageView;

        }

    }



    
      
      
        public
      
      
        void
      
       loadBitmap(
      
        int
      
      
         resId, ImageView imageView) {

        
      
      
        if
      
      
         (cancelPotentialWork(resId, imageView)) {

            
      
      
        final
      
       BitmapWorkerTask task = 
      
        new
      
      
         BitmapWorkerTask(imageView);

            
      
      
        final
      
       AsyncDrawable asyncDrawable =

                    
      
        new
      
      
         AsyncDrawable(getResources(), mPlaceHolderBitmap, task);

            imageView.setImageDrawable(asyncDrawable);

            task.execute(resId);

        }

    }



    
      
      
        static
      
      
        class
      
       AsyncDrawable 
      
        extends
      
      
         BitmapDrawable {

        
      
      
        private
      
      
        final
      
       WeakReference<BitmapWorkerTask>
      
         bitmapWorkerTaskReference;



        
      
      
        public
      
      
         AsyncDrawable(Resources res, Bitmap bitmap,

                BitmapWorkerTask bitmapWorkerTask) {

            
      
      
        super
      
      
        (res, bitmap);

            bitmapWorkerTaskReference 
      
      =

                
      
        new
      
       WeakReference<BitmapWorkerTask>
      
        (bitmapWorkerTask);

        }



        
      
      
        public
      
      
         BitmapWorkerTask getBitmapWorkerTask() {

            
      
      
        return
      
      
         bitmapWorkerTaskReference.get();

        }

    }



    
      
      
        public
      
      
        static
      
      
        boolean
      
       cancelPotentialWork(
      
        int
      
      
         data, ImageView imageView) {

        
      
      
        final
      
       BitmapWorkerTask bitmapWorkerTask =
      
         getBitmapWorkerTask(imageView);



        
      
      
        if
      
       (bitmapWorkerTask != 
      
        null
      
      
        ) {

            
      
      
        final
      
      
        int
      
       bitmapData =
      
         bitmapWorkerTask.data;

            
      
      
        if
      
       (bitmapData !=
      
         data) {

                
      
      
        //
      
      
         Cancel previous task
      
      

                bitmapWorkerTask.cancel(
      
        true
      
      
        );

            } 
      
      
        else
      
      
         {

                
      
      
        //
      
      
         The same work is already in progress
      
      
        return
      
      
        false
      
      
        ;

            }

        }

        
      
      
        //
      
      
         No task associated with the ImageView, or an existing task was cancelled
      
      
        return
      
      
        true
      
      
        ;

    }



    
      
      
        private
      
      
        static
      
      
         BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {

       
      
      
        if
      
       (imageView != 
      
        null
      
      
        ) {

           
      
      
        final
      
       Drawable drawable =
      
         imageView.getDrawable();

           
      
      
        if
      
       (drawable 
      
        instanceof
      
      
         AsyncDrawable) {

               
      
      
        final
      
       AsyncDrawable asyncDrawable =
      
         (AsyncDrawable) drawable;

               
      
      
        return
      
      
         asyncDrawable.getBitmapWorkerTask();

           }

        }

        
      
      
        return
      
      
        null
      
      
        ;

    }



    ... 
      
      
        //
      
      
         include updated BitmapWorkerTask class
      
    

Note:

同樣的代碼也可以應用于 ListView

這樣的實現對于如何處理和加載圖片保留了足夠的彈性,從而不會引起UI的卡頓。在后臺任務中,你可以從網絡上讀取圖片或者將大尺寸的數碼照片進行縮放,在任務完成后,圖像會顯示出來。

要看這系列課程的完整代碼樣例,請下載 http://www.cnblogs.com/jdneo/p/3512517.html 中的樣例代碼

【Android Developers Training】 60. 在你的UI中顯示位圖


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 中国美女一级a毛片录像在线 | 伊色综合久久之综合久久 | 久久精品国产视频 | 一级午夜| 激情综合网婷婷 | 日本欧美三级 | 欧美综合色区 | 亚洲激情视频在线播放 | 国产色婷婷精品综合在线手机播放 | 青青青国产成人久久111网站 | 一区二区三区四区视频在线观看 | 久久亚洲国产成人精品性色 | 91香蕉国产亚洲一区二区三区 | 亚洲欧美日韩人成 | 精品国产品香蕉在线 | 久久99精品久久久久子伦 | 国产精品日日做人人爱 | 国内自拍青青草 | 一区二区三区免费视频网站 | 国产大片免费观看中文字幕 | 前田香织一区二区中文字幕 | 高清欧美一区二区免费影视 | 女人18毛片特级一级免费视频 | 在线观看国产精美视频 | 1000部羞羞禁止免费观看视频 | 一区二区三区四区视频在线观看 | 美女久久久 | 国产精品久久久久激情影院 | 天天干夜夜爽天天操夜夜爽视频 | 中文字幕免费在线视频 | 国产精品资源 | 在线综合 亚洲 欧美中文字幕 | 九操网 | 亚洲精品国产福利在线观看 | 884hutv四虎永久黄网 | 国产成人亚洲精品乱码在线观看 | 成人毛片免费在线观看 | 国产在线一区二区三区 | 久久久精品成人免费看 | 亚洲精品国产综合一线久久 | 色综合亚洲综合网站综合色 |