日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android ListView性能优化实例讲解

發(fā)布時(shí)間:2023/12/18 Android 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android ListView性能优化实例讲解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言:

? 對(duì)于ListView,大家絕對(duì)都不會(huì)陌生,只要是做過Android開發(fā)的人,哪有不用ListView的呢?

? 只要是用過ListView的人,哪有不關(guān)心對(duì)它性能優(yōu)化的呢?

? 關(guān)于如何對(duì)ListView進(jìn)行性能優(yōu)化,不僅是面試中常常會(huì)被問到的(我前段時(shí)間面試了幾家公司,全部都問到了這個(gè)問題了),而且在實(shí)際項(xiàng)目中更是非常重要的一環(huán),它甚至在某種程度上決定了用戶是否喜歡接受你的APP。(如果你的列表滑起來很卡,我敢說很多人會(huì)直接卸載)

? 網(wǎng)上關(guān)于如何對(duì)ListView進(jìn)行性能優(yōu)化,提出了很多方案。但是我搜過很多資料,卻感覺很多文章都寫得比較模糊,沒有代碼說明,讓我感到很累。要知道能給程序員最直接感官刺激的,當(dāng)然是代碼啦!!!


一、Listview 性能優(yōu)化方案

  1).復(fù)用convertView

? ? 在getItemView中,判斷convertView是否為空,如果不為空,可復(fù)用。如果couvertview中的view需要添加listerner,代碼一定要在if(convertView==null){}之外。

  2).異步加載圖片

? ? item中如果包含有webimage,那么最好異步加載

  3).快速滑動(dòng)時(shí)不顯示圖片

? ? 當(dāng)快速滑動(dòng)列表時(shí)(SCROLL_STATE_FLING),item中的圖片或獲取需要消耗資源的view,可以不顯示出來;而處于其他兩種狀態(tài)(SCROLL_STATE_IDLE 和SCROLL_STATE_TOUCH_SCROLL),則將那些view顯示出來


二、實(shí)戰(zhàn)講解如何優(yōu)化ListView

? ? 2.1 我們先定義一個(gè)ListView

<ListViewandroid:id="@+id/listview"android:layout_width="fill_parent"android:layout_height="fill_parent"android:divider="#7A7A7A"android:dividerHeight="10dp"/>

? ? 2.2 然后我們?nèi)懸粋€(gè)網(wǎng)絡(luò)請(qǐng)求,獲取網(wǎng)絡(luò)的json字符串。

? ? 這里,我們用到xutils框架的httputil,通過它,可以很方便的進(jìn)行網(wǎng)絡(luò)請(qǐng)求。 至于請(qǐng)求的url,我們使用慕課網(wǎng)提供的視頻數(shù)據(jù)列表接口“http://www.imooc.com/api/teacher?type=4&num=30”。先讓我們看下我寫的一個(gè)HTTP請(qǐng)求的工具類:

import android.content.Context;import com.lidroid.xutils.HttpUtils; import com.lidroid.xutils.exception.HttpException; import com.lidroid.xutils.http.RequestParams; import com.lidroid.xutils.http.ResponseInfo; import com.lidroid.xutils.http.callback.RequestCallBack; import com.lidroid.xutils.http.client.HttpRequest.HttpMethod; import com.lidroid.xutils.util.LogUtils;/*** 網(wǎng)絡(luò)請(qǐng)求工具類** @author lining*/ public class HttpUtil {/*** 請(qǐng)求的根URL地址*/public static final String BASE_URL = "http://www.imooc.com/api/teacher?type=4&num=50";public static void sendRequest(final Context context,final HttpMethod method, RequestParams params,final IOAuthCallBack iOAuthCallBack) {HttpUtils http = new HttpUtils();http.configCurrentHttpCacheExpiry(1000 * 5);// 設(shè)置超時(shí)時(shí)間http.configTimeout(5 * 1000);http.configSoTimeout(5 * 1000);if (method == HttpMethod.GET) {http.configCurrentHttpCacheExpiry(5000); // 設(shè)置緩存5秒,5秒內(nèi)直接返回上次成功請(qǐng)求的結(jié)果。}http.send(method, BASE_URL, params,new RequestCallBack<String>() {@Overridepublic void onStart() {LogUtils.d(method.name() + " request is onStart.......");}@Overridepublic void onSuccess(ResponseInfo<String> responseInfo) {LogUtils.d("statusCode:" + responseInfo.statusCode + " ----->" + responseInfo.result);iOAuthCallBack.getIOAuthCallBack(responseInfo.result);// 利用接口回調(diào)數(shù)據(jù)傳輸}@Overridepublic void onFailure(HttpException error, String msg) {LogUtils.d("statusCode:" + error.getExceptionCode() + " -----> " + msg);iOAuthCallBack.getIOAuthCallBack("FF");// 利用接口回調(diào)數(shù)據(jù)傳輸}});} }? 工具類其實(shí)并沒有啥特別之處,無非就是利用Xutils框架的HttpUtil發(fā)送網(wǎng)絡(luò)請(qǐng)求,獲取數(shù)據(jù)。 方法參數(shù)里,我們加入了一個(gè)IOAuthCallBack回調(diào)接口,該接口主要用戶在Activity和工具類之間回調(diào)請(qǐng)求結(jié)果數(shù)據(jù)。

/*** 數(shù)據(jù)請(qǐng)求回調(diào)接口*/ public interface IOAuthCallBack {// 成功public void getIOAuthCallBack(String result); }

? ? 下面,我們Activity發(fā)送一個(gè)網(wǎng)絡(luò)請(qǐng)求,獲取json數(shù)據(jù),并回調(diào)處理:

private void qryDataFromServer() {HttpUtil.sendRequest(this, HttpRequest.HttpMethod.GET, null, this);}@Overridepublic void getIOAuthCallBack(String result) {RspData rspData = GsonUtil.getGson().fromJson(result, RspData.class);// 更新UI列表KechengAdapter mAdapter = new KechengAdapter(this, rspData.data);listview.setAdapter(mAdapter);}


這里關(guān)于json數(shù)據(jù)的解析使用的GSON,無啥特別說明之處,把實(shí)體類的代碼貼出來看下:

public class RspData {public String status;public List<KeCheng> data;public String msg; }
public class KeCheng {public String id;public String name;public String picSmall;public String picBig;public String description;public String learner; }

? ? 2.3 有了集合數(shù)據(jù)之后,去定義BaseAdapter

? ?在此之前,我們先看下list item的布局文件:list_item_kecheng.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:id="@+id/picBig"android:layout_width="fill_parent"android:layout_height="180dp"android:scaleType="fitXY"android:src="@mipmap/ic_launcher"/><TextViewandroid:id="@+id/name"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="CSS動(dòng)畫實(shí)用技巧"android:singleLine="true"android:padding="10dp"android:textSize="15sp"/><TextViewandroid:id="@+id/description"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="教你使用CSS實(shí)現(xiàn)驚艷的動(dòng)畫效果!"android:textSize="12sp"android:lines="2"android:padding="10dp"/></LinearLayout>


? 接下來,讓我們好好看看Adapter是如何定義的:

import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView;import java.util.List;public class KechengAdapter extends BaseAdapter {private Context mContext;private LayoutInflater mInflater;private List<KeCheng> mDatas;public KechengAdapter(Context context, List<KeCheng> datas) {mContext = context;mInflater = LayoutInflater.from(mContext);mDatas = datas;}@Overridepublic int getCount() {return (mDatas != null ? mDatas.size() : 0);}@Overridepublic Object getItem(int position) {return (mDatas != null ? mDatas.get(position) : null);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder holder = null;if (convertView == null) {convertView = mInflater.inflate(R.layout.list_item_kecheng, null);holder = new ViewHolder();holder.picBig = (ImageView) convertView.findViewById(R.id.picBig);holder.name = (TextView) convertView.findViewById(R.id.name);holder.description = (TextView) convertView.findViewById(R.id.description);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}final KeCheng keCheng = mDatas.get(position);if (keCheng != null) {ImageLoaderUtil.getInstance().displayListItemImage(keCheng.picBig, holder.picBig);holder.name.setText(keCheng.name);holder.description.setText(keCheng.description);}return convertView;}static class ViewHolder {ImageView picBig;TextView name;TextView description;} }

? ?ListView性能優(yōu)化的重點(diǎn)就是如何去處理BaseAdapter,且看上面的代碼,我們?cè)趃etView中,判斷convertView是否為空,如果不為空,可復(fù)用。如何復(fù)用的呢?

??我們通過convertview的setTag方法和getTag方法來將我們要顯示的數(shù)據(jù)來綁定在convertview上。如果convertview 是第一次展示我們就創(chuàng)建新的Holder對(duì)象與之綁定,并在最后通過return convertview 返回,去顯示;如果convertview 是回收來的那么我們就不必創(chuàng)建新的holder對(duì)象,只需要把原來的綁定的holder取出加上新的數(shù)據(jù)就行了。

? ?如果couvertview中的view需要添加listerner,代碼一定要在if(convertView==null){}之外。


? ?看代碼夠仔細(xì)的人能夠發(fā)現(xiàn)有這么一行代碼,ImageLoaderUtil.getInstance().displayListItemImage(keCheng.picBig, holder.picBig); 這是使用的圖片異步加載框架Universal-Image-Loader來完成對(duì)網(wǎng)絡(luò)圖片的異步加載、緩存,(強(qiáng)烈推薦使用)使用這個(gè)開源框架后,我們就無需再為如何加載緩存網(wǎng)絡(luò)圖片煩惱啦!

? ?快隨我一起看看如何配置這個(gè)框架吧:

import android.content.Context; import android.graphics.Bitmap; import android.widget.ImageView;import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator; import com.nostra13.universalimageloader.cache.memory.impl.UsingFreqLimitedMemoryCache; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.assist.QueueProcessingType;import java.io.File;/*** 配置全局的 Android-Universal-Image-Loader*/ public class ImageLoaderUtil {private static ImageLoaderUtil instance = null;private ImageLoader mImageLoader;// 列表中默認(rèn)的圖片private DisplayImageOptions mListItemOptions;// 頭像圖片private DisplayImageOptions mUserHeadOptions;private ImageLoaderUtil(Context context) {mImageLoader = ImageLoader.getInstance();mListItemOptions = new DisplayImageOptions.Builder()// 設(shè)置圖片Uri為空或是錯(cuò)誤的時(shí)候顯示的圖片.showImageForEmptyUri(R.mipmap.load_default_img).showStubImage(R.mipmap.load_default_img)// 設(shè)置圖片加載/解碼過程中錯(cuò)誤時(shí)候顯示的圖片.showImageOnFail(R.mipmap.load_default_img)// 加載圖片時(shí)會(huì)在內(nèi)存、磁盤中加載緩存.cacheInMemory().cacheOnDisc().bitmapConfig(Bitmap.Config.RGB_565).delayBeforeLoading(300).build();}public static ImageLoaderUtil getInstance() {return instance;}public synchronized static ImageLoaderUtil init(Context context) {if (instance == null) {instance = new ImageLoaderUtil(context);}File cacheDir = context.getExternalFilesDir("news/pictures");ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context).threadPriority(Thread.NORM_PRIORITY - 2).denyCacheImageMultipleSizesInMemory()// .imageDownloader(imageDownloader).imageDecoder(imageDecoder).discCacheFileNameGenerator(new Md5FileNameGenerator()).tasksProcessingOrder(QueueProcessingType.LIFO).memoryCacheExtraOptions(360, 360).memoryCache(new UsingFreqLimitedMemoryCache(4 * 1024 * 1024)).discCache(new UnlimitedDiscCache(cacheDir)).build();// Initialize ImageLoader with configuration.ImageLoader.getInstance().init(config);return instance;}/*** 列表圖片** @param uri* @param imageView*/public void displayListItemImage(String uri, ImageView imageView) {String strUri = (isEmpty(uri) ? "" : uri);mImageLoader.displayImage(strUri, imageView, mListItemOptions);}public ImageLoader getImageLoader() {return mImageLoader;}private boolean isEmpty(String str) {if (str != null && str.trim().length() > 0 && !str.equalsIgnoreCase("null")) {return false;}return true;} }


? ?這是我寫好的一個(gè)Universal-Image-Loader的工具類,以后可以直接使用它進(jìn)行圖片的下載緩存處理了。 當(dāng)然在使用前,還需要進(jìn)行初始化它,我們推薦在Application中對(duì)其進(jìn)行初始化操作:

public class MyApp extends Application {public static Context context;@Overridepublic void onCreate() {super.onCreate();context = this;ImageLoaderUtil.init(context);} }? ?

? ? 2.4 處理快速滑動(dòng)時(shí)暫停加載圖片

? ? ?我們知道,當(dāng)快速滑動(dòng)列表時(shí)(SCROLL_STATE_FLING),item中的圖片獲取需要消耗資源的View,可以不顯示出來(因?yàn)榛瑒?dòng)的過快,我們也不需要看圖片啊);而處于其他兩種狀態(tài)(SCROLL_STATE_IDLE 和SCROLL_STATE_TOUCH_SCROLL),則將那些view顯示出來。

? ? ?那如何實(shí)現(xiàn)呢? 這里我還是推薦使用Universal-Image-Loader已經(jīng)為大家封裝好了的方法,(當(dāng)然,別的框架,如Xutils也封裝了相關(guān)的方法)。Universal-Image-Loader框架的com.nostra13.universalimageloader.core.assist.PauseOnScrollListener監(jiān)聽器已經(jīng)封裝了對(duì)滾動(dòng)時(shí)圖片處理的監(jiān)聽,我們只需要在為ListView組件設(shè)置滾動(dòng)監(jiān)聽的時(shí)候,把PauseOnScrollListener的實(shí)例傳入即可。這里,有必要讓大家先看下PauseOnScrollListener的源碼:

public class PauseOnScrollListener implements OnScrollListener {private ImageLoader imageLoader;private final boolean pauseOnScroll;private final boolean pauseOnFling;private final OnScrollListener externalListener;public PauseOnScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling) {this(imageLoader, pauseOnScroll, pauseOnFling, (OnScrollListener)null);}public PauseOnScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling, OnScrollListener customListener) {this.imageLoader = imageLoader;this.pauseOnScroll = pauseOnScroll;this.pauseOnFling = pauseOnFling;this.externalListener = customListener;}public void onScrollStateChanged(AbsListView view, int scrollState) {switch(scrollState) {case 0:this.imageLoader.resume();break;case 1:if(this.pauseOnScroll) {this.imageLoader.pause();}break;case 2:if(this.pauseOnFling) {this.imageLoader.pause();}}if(this.externalListener != null) {this.externalListener.onScrollStateChanged(view, scrollState);}}public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {if(this.externalListener != null) {this.externalListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);}} }? ? 大家可以看到,PauseOnScrollListener實(shí)現(xiàn)了OnScrollListener接口,這也就是剛剛為啥說可以把PauseOnScrollListener的實(shí)例設(shè)置到ListView監(jiān)聽器的原因。PauseOnScrollListener有兩個(gè)重要的構(gòu)造方法,其中參數(shù)pauseOnScroll控制我們緩慢滑動(dòng)ListView,GridView是否停止加載圖片,pauseOnFling 控制猛的滑動(dòng)ListView,GridView是否停止加載圖片。而另一個(gè)參數(shù)OnScrollListener customListener則可以用于留給開發(fā)者繼續(xù)回到處理相應(yīng)的滑動(dòng)監(jiān)聽事件,比如列表是否滑動(dòng)到了最后等等。

? ? ? 知道了如何利用PauseOnScrollListener,那我們?cè)贏ctivity之中只需要設(shè)置一句簡(jiǎn)單的監(jiān)聽代碼即可:

listview.setOnScrollListener(new PauseOnScrollListener(ImageLoaderUtil.getInstance().getImageLoader(), false, true));
? ? ? 如何你的項(xiàng)目需要下來刷新或者是滑動(dòng)加載等功能,你又必須提供滑動(dòng)事件的回調(diào)參數(shù):

listview.setOnScrollListener(new PauseOnScrollListener(ImageLoaderUtil.getInstance().getImageLoader(), false, true, onScrollListener)); private AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() {@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {switch (scrollState) {case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:// 觸摸后滾動(dòng)break;case AbsListView.OnScrollListener.SCROLL_STATE_FLING:// 滾動(dòng)狀態(tài)break;case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:// 空閑狀態(tài)if (view.getLastVisiblePosition() == view.getCount() - 1) {System.out.println("************滾動(dòng)到了最后一個(gè)***************");}break;}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}};
好啦,這樣做出的ListView已經(jīng)很完美了,讓我們欣賞下它的效果吧:




結(jié)束語:

? ? 本文主要通過三個(gè)方面:1、復(fù)用convertView;2、異步加載圖片; 3、ListView快速滑動(dòng)時(shí)不顯示圖片介紹了如何對(duì)ListView進(jìn)行性能優(yōu)化,這是最常見也是最重要的三個(gè)方面,建議大家務(wù)必將其使用在自己項(xiàng)目的開發(fā)中,以提高列表的易用性!

? ? ?當(dāng)然,文章還提到了兩個(gè)第三方框架的使用:Xutils和Universal-Image-Loader,這是兩個(gè)非常使用的框架,建議大家也能學(xué)習(xí)下。

? ? 如果大家還有別的優(yōu)化方案,建議提出來,共同學(xué)習(xí),共同進(jìn)步。


源碼下載地址:http://download.csdn.net/detail/zuiwuyuan/9055795

Gitub下載地址:https://github.com/zuiwuyuan/ListViewOptimized

轉(zhuǎn)載于:https://www.cnblogs.com/hehe520/p/6329978.html

總結(jié)

以上是生活随笔為你收集整理的Android ListView性能优化实例讲解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。