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

【Android Developers Training】 60. 在你的UI

系統(tǒng) 2119 0

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

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


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


一). 實(shí)現(xiàn)向一個ViewPager加載位圖

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

Note:

如果你有更小數(shù)量的圖片,并確信他們能滿足應(yīng)用的內(nèi)存限制,那么使用平常的 PagerAdapter FragmentPagerAdapter 會更合適一些。

下面是一個具有 ImageView ViewPager 實(shí)現(xiàn)。主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);

        }

    }

}
      
    

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

      
        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
      
      
            }

}
      
    

很好,你發(fā)現(xiàn)了問題所在:圖片時在UI線程上進(jìn)行讀取的,因此可能會導(dǎo)致應(yīng)用停止響應(yīng)從而崩潰。使用一個在 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);

        }

    }

}
      
    

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

      
        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
      
      

}
    

將所有代碼片段放在一起,組成了響應(yīng)良好的 ViewPager 實(shí)現(xiàn),它有很小的圖片加載延遲,并且有能力在后臺根據(jù)你的需要處理圖片。


二).?實(shí)現(xiàn)向一個GridView加載位圖

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

我們首先來看一下一個標(biāo)準(zhǔn)的 GridView 實(shí)現(xiàn),它有一個置于 Fragment 中的子 ImageView 。還是像之前一樣,請讀者思考這一看上去完美的實(shí)現(xiàn)是否有進(jìn)一步提升的空間?

      
        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;

        }

    }

}
      
    

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

之前章節(jié)的異步處理和緩存的方法可以在這里實(shí)現(xiàn)。然而,你也需要警惕并發(fā)的問題,因?yàn)? 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:

同樣的代碼也可以應(yīng)用于 ListView

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

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

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


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产区精品一区二区不卡中文 | 国产欧美日韩网站 | 九九热视频在线 | 亚洲网站在线看 | 九九夜夜| 亚洲精品高清国产一线久久97 | 欧美在线播放成人免费 | 天天拍天天操 | 99久久精品久久久久久婷婷 | www.777奇米| 欧美另类久久久精品 | 男女污污视频在线观看 | 亚洲一区二区三区国产精品 | 六月丁香婷婷激情国产 | 天天干天天爽天天射 | 国产欧美精品一区二区三区四区 | 国内精品视频在线观看 | 久久久噜噜噜久久网 | 久久高清一区二区三区 | 精品中文字幕在线 | 日本国产一区二区三区 | 99这里都是精品 | 在线a视频| 久久九九久精品国产 | 国产短视频精品区第一页 | 久久精品只有这里有 | 俄罗斯美女逼 | a一级毛片视频免费看 | 最新中文字幕日本 | 一级全黄色毛片 | 天天干天天射天天舔 | 天天爽夜夜爽天天做夜夜做 | 亚洲精品国产美女在线观看 | 成人亚洲欧美综合 | 久久r热这里有精品视频 | 精品色 | 成人高清毛片a | 免费在线精品视频 | 欧日韩不卡在线视频 | 日韩成人精品在线 | 欧美一区在线观看视频 |