Android性能调优实例
生活随笔
收集整理的這篇文章主要介紹了
Android性能调优实例
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本文主要分享自己在appstore項(xiàng)目中的性能調(diào)優(yōu)點(diǎn),包括
同步改異步、緩存、Layout優(yōu)化、數(shù)據(jù)庫優(yōu)化、算法優(yōu)化、延遲執(zhí)行等。
一、性能瓶頸點(diǎn)
整個(gè)頁面主要由6個(gè)Page的ViewPager,每個(gè)Page為一個(gè)GridView,GridView一屏大概顯示4*4的item信息(本文最后有附圖)。由于網(wǎng)絡(luò)數(shù)據(jù)獲取較多且隨時(shí)需要保持頁面內(nèi)app下載進(jìn)度及狀態(tài),所以出現(xiàn)以下性能問題
a.??ViewPager左右滑動(dòng)明顯卡頓
b.??GridView上下滾動(dòng)明顯卡頓
c.??其他Activity返回ViewPager Activity較慢
d.??網(wǎng)絡(luò)獲取到展現(xiàn)速度較慢
二、性能調(diào)試及定位
主要使用 Traceview、monkey、monkey runner調(diào)試,traceview類似java web調(diào)優(yōu)的visualvm,使用方法如下:
在需要調(diào)優(yōu)的activity onCreate函數(shù)中添加<font style="background-color:rgb(254, 253, 231)"><font face="Georgia,">android.os.debug.startMethodTracing("Entertainment");</font></font> 復(fù)制代碼
onDestrory函數(shù)中添加
<font style="background-color:rgb(254, 253, 231)"><font face="Georgia,">android.os.debug.stopMethodTracing();</font></font> 復(fù)制代碼
程序退出后會(huì)在sd卡根目錄下生成Entertainment.trace這個(gè)文件,cmd到android sdk的tools目錄下運(yùn)行traceview.bat Entertainment.trace即可,截圖如下
從中可以看出各個(gè)函數(shù)的調(diào)用時(shí)間、調(diào)用次數(shù)、平均調(diào)用時(shí)間、時(shí)間占用百分比等從而定位到耗時(shí)的操作。monkey、monkey runner更詳細(xì)的見后面博客介紹
三、性能調(diào)優(yōu)點(diǎn)
主要包括同步改異步、緩存、Layout優(yōu)化、數(shù)據(jù)庫優(yōu)化、算法優(yōu)化、延遲執(zhí)行。
1. 同步改異步
這個(gè)就不用多講了,耗時(shí)操作放在線程中執(zhí)行防止占用主線程,一定程度上解決anr。
但需要注意線程和service結(jié)合(防止activity被回收后線程也被回收)以及線程的數(shù)量(后面優(yōu)化介紹)
PS:請(qǐng)使用java的線程池(后面介紹),少使用AsyncTask,因?yàn)锳syncTask存在性能問題(以后會(huì)單獨(dú)博文介紹)
2. 緩存
java的對(duì)象創(chuàng)建需要分配資源較耗費(fèi)時(shí)間,加上創(chuàng)建的對(duì)象越多會(huì)造成越頻繁的gc影響系統(tǒng)響應(yīng)。主要使用單例模式、緩存(圖片緩存、線程池、View緩存、IO緩存、消息緩存、通知欄notification緩存)及其他方式減少對(duì)象創(chuàng)建。
(1). 單例模式
對(duì)于創(chuàng)建開銷較大的類可使用此方法,保證全局一個(gè)實(shí)例,在程序運(yùn)行過程中該類不會(huì)因新建額外對(duì)象產(chǎn)生開銷。示例代碼如下:class Singleton {
? ? private static Singleton instance = null;
? ? private Singleton() {
? ?? ???}
? ? public static synchronized Singleton getInstance() {
? ?? ???if (instance == null) {
? ?? ?? ?? ?instance = new Singleton();
? ?? ???}
? ?? ???return instance;
? ? }
} 復(fù)制代碼
(2). 緩存
程序中用到了圖片緩存、線程池、View緩存、IO緩存、消息緩存、通知欄notification緩存等。
a. 圖片緩存:見ImageCache和ImageSdCache
b. 線程池:使用Java的Executors類,通過newCachedThreadPool、newFixedThreadPool、newSingleThreadExecutor、newScheduledThreadPool提供四種不同類型的線程池
c. View緩存:@Override
public View getView(int position, View convertView, ViewGroup parent) {
? ?? ???ViewHolder holder;
? ?? ???if (convertView == null) {
? ?? ?? ?? ?? ? convertView = inflater.inflate(R.layout.type_item, null);
? ?? ?? ?? ?? ? holder = new ViewHolder();
? ?? ?? ?? ?? ? holder.imageView = (ImageView)convertView.findViewById(R.id.app_icon);
? ?? ?? ?? ?? ? holder.textView = (TextView)convertView.findViewById(R.id.app_name);
? ?? ?? ?? ?? ? convertView.setTag(holder);
? ?? ???} else {
? ?? ?? ?? ?? ? holder = (ViewHolder)convertView.getTag();
? ?? ???}
? ?? ???holder.imageView.setImageResource(R.drawable.index_default_image);
? ?? ???holder.textView.setText("");
? ?? ???return convertView;
}
/**
* ViewHolder
*/
static class ViewHolder {
? ?? ???ImageView imageView;
? ?? ???TextView??textView;
} 復(fù)制代碼
通過convertView是否為null減少layout inflate次數(shù),通過靜態(tài)的ViewHolder減少findViewById的次數(shù),這兩個(gè)函數(shù)尤其是inflate是相當(dāng)費(fèi)時(shí)間的
d. IO緩存:
使用具有緩存策略的輸入流,BufferedInputStream替代InputStream,BufferedReader替代Reader,BufferedReader替代BufferedInputStream.對(duì)文件、網(wǎng)絡(luò)IO皆適用。
e. 消息緩存:通過Handler的obtainMessage回收就的Message對(duì)象,減少M(fèi)essage對(duì)象的創(chuàng)建開銷
handler.sendMessage(handler.obtainMessage(1));
f. 通知欄notification緩存:下載中需要不斷改變通知欄進(jìn)度條狀態(tài),如果不斷新建Notification會(huì)導(dǎo)致通知欄很卡。這里我們可以使用最簡(jiǎn)單的緩存
Map<String, Notification> notificationMap = new HashMap<String, Notification>();如果notificationMap中不存在,則新建notification并且put into map.
(3). 其他
能創(chuàng)建基類解決問題就不用具體子類:除需要設(shè)置優(yōu)先級(jí)的線程使用new Thread創(chuàng)建外,其余線程創(chuàng)建使用new Runnable。因?yàn)樽宇悤?huì)有自己的屬性創(chuàng)建需要更多開銷。
控制最大并發(fā)數(shù)量:使用Java的Executors類,通過Executors.newFixedThreadPool(nThreads)控制線程池最大線程并發(fā)
對(duì)于http請(qǐng)求增加timeout 3. Layout優(yōu)化
性能優(yōu)化相關(guān)的一些標(biāo)簽 <viewStub/>,<merge/>和<include/> 可見: http://hexen.blog.51cto.com/1110171/820197
TextView屬性優(yōu)化:TextView的android:ellipsize=”marquee”跑馬燈效果極耗性能,具體原因還在深入源碼中
對(duì)于layout中的布局實(shí)際效果可使用hierarchyviewer查看
對(duì)于layout中多余的view以及不正確的標(biāo)簽可使用android lint查看
4. 數(shù)據(jù)庫優(yōu)化
主要包括sql優(yōu)化、建立索引、使用事務(wù)、讀寫表區(qū)分
(1). sql優(yōu)化
可參考http://database.51cto.com/art/200904/118526.htm
(2). 建立索引
使用CREATE INDEX mycolumn_index ON mytable (myclumn)語句在SQLiteOpenHelper子類的onCreate或onUpgrade函數(shù)創(chuàng)建索引,索引創(chuàng)建后對(duì)大數(shù)據(jù)量的查詢性能提升效果較明顯(3). 使用事務(wù)
事務(wù)不僅能保證批量操作一起完成或回滾,而且在大量插入、更新、查詢時(shí)減少程序和表的交互從而提高性能SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();
try {
? ?? ???// add to do
? ?? ???db.setTransactionSuccessful();
} catch (Exception e) {
? ?? ???Log.e(TAG, e.toString());
} finally {
? ?? ???db.endTransaction();
} 復(fù)制代碼
(4). 讀寫表區(qū)分對(duì)于查詢操作使用dbHelper.getReadableDatabase();讀表代替寫表。因?yàn)閟qlite是表級(jí)鎖,所以修改和插入等寫操作的性能較差。
5. 算法優(yōu)化
這個(gè)就是個(gè)博大精深的話題了,只介紹本應(yīng)用中使用的。
使用hashMap代替arrayList,時(shí)間復(fù)雜度降低一個(gè)數(shù)量級(jí)
6. 延遲執(zhí)行
對(duì)于很多耗時(shí)邏輯沒必要立即執(zhí)行,這時(shí)候我們可以將其延遲執(zhí)行。
線程延遲執(zhí)行 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
消息延遲發(fā)送 handler.sendMessageDelayed(handler.obtainMessage(0), 1000);
四、本程序性能調(diào)優(yōu)結(jié)果
1. ViewPager左右滑動(dòng)明顯卡頓
2. GridView上下滾動(dòng)明顯卡頓
(1). 去掉TextView的android:ellipsize=”marquee”
(2). 修改圖片緩存的最大線程數(shù),增加http timeout
(3). 修改設(shè)置app是否已安裝的狀態(tài),具體代碼修改如下:List<PackageInfo> installedPackageList = getPackageManager().getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
List<App> installedAppList = function(installedAppList)
for (App app : appList) {
? ?? ???for (App installedApp : installedAppList) {
? ?? ???}
} 復(fù)制代碼
修改為
for (App app : appList) {
? ?? ???Pair<Integer, String> versionInfo = INSTALLED_APP_MAP.get(app.getPackageName());
? ?? ???if (versionInfo != null) {
? ?? ???} else {
? ?? ???}
} 復(fù)制代碼
從每次獲取List<PackageInfo> installedAppList = getPackageManager().getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);修改為只在有應(yīng)用安裝或卸載廣播時(shí)獲取應(yīng)用列表,并且用hashMap代替installedAppList減少查詢時(shí)間。將平均執(zhí)行時(shí)間從201ms降低到1ms。
3. 其他Activity返回ViewPager Activity較慢
定位:在onStart函數(shù)
解決:使用延遲策略,具體代碼修改如下:@Override
public void onStart() {
? ?? ???super.onStart();
? ?? ???appUpdateListAdapter.notifyDataSetChanged();
} 復(fù)制代碼
4. 網(wǎng)絡(luò)獲取到展現(xiàn)速度較慢定位:在HttpURLConnection.getInputStream()之后的處理
解決:使用BufferedReader替代BufferedInputStream獲取時(shí)間從100ms降低到3ms,具體代碼修改如下:HttpURLConnection con = (HttpURLConnection)url.openConnection();
InputStream input = con.getInputStream();
while (input.read(buffer, 0, 1024) != -1) {
} 復(fù)制代碼
改為
HttpURLConnection con = (HttpURLConnection)url.openConnection();
BufferedReader input = new BufferedReader(new InputStreamReader(con.getInputStream()));
String s;
while ((s = input.readLine()) != null) {
} 復(fù)制代碼
一、性能瓶頸點(diǎn)
整個(gè)頁面主要由6個(gè)Page的ViewPager,每個(gè)Page為一個(gè)GridView,GridView一屏大概顯示4*4的item信息(本文最后有附圖)。由于網(wǎng)絡(luò)數(shù)據(jù)獲取較多且隨時(shí)需要保持頁面內(nèi)app下載進(jìn)度及狀態(tài),所以出現(xiàn)以下性能問題
a.??ViewPager左右滑動(dòng)明顯卡頓
b.??GridView上下滾動(dòng)明顯卡頓
c.??其他Activity返回ViewPager Activity較慢
d.??網(wǎng)絡(luò)獲取到展現(xiàn)速度較慢
二、性能調(diào)試及定位
主要使用 Traceview、monkey、monkey runner調(diào)試,traceview類似java web調(diào)優(yōu)的visualvm,使用方法如下:
在需要調(diào)優(yōu)的activity onCreate函數(shù)中添加
從中可以看出各個(gè)函數(shù)的調(diào)用時(shí)間、調(diào)用次數(shù)、平均調(diào)用時(shí)間、時(shí)間占用百分比等從而定位到耗時(shí)的操作。monkey、monkey runner更詳細(xì)的見后面博客介紹
三、性能調(diào)優(yōu)點(diǎn)
主要包括同步改異步、緩存、Layout優(yōu)化、數(shù)據(jù)庫優(yōu)化、算法優(yōu)化、延遲執(zhí)行。
1. 同步改異步
這個(gè)就不用多講了,耗時(shí)操作放在線程中執(zhí)行防止占用主線程,一定程度上解決anr。
但需要注意線程和service結(jié)合(防止activity被回收后線程也被回收)以及線程的數(shù)量(后面優(yōu)化介紹)
PS:請(qǐng)使用java的線程池(后面介紹),少使用AsyncTask,因?yàn)锳syncTask存在性能問題(以后會(huì)單獨(dú)博文介紹)
2. 緩存
java的對(duì)象創(chuàng)建需要分配資源較耗費(fèi)時(shí)間,加上創(chuàng)建的對(duì)象越多會(huì)造成越頻繁的gc影響系統(tǒng)響應(yīng)。主要使用單例模式、緩存(圖片緩存、線程池、View緩存、IO緩存、消息緩存、通知欄notification緩存)及其他方式減少對(duì)象創(chuàng)建。
(1). 單例模式
對(duì)于創(chuàng)建開銷較大的類可使用此方法,保證全局一個(gè)實(shí)例,在程序運(yùn)行過程中該類不會(huì)因新建額外對(duì)象產(chǎn)生開銷。示例代碼如下:
程序中用到了圖片緩存、線程池、View緩存、IO緩存、消息緩存、通知欄notification緩存等。
a. 圖片緩存:見ImageCache和ImageSdCache
b. 線程池:使用Java的Executors類,通過newCachedThreadPool、newFixedThreadPool、newSingleThreadExecutor、newScheduledThreadPool提供四種不同類型的線程池
c. View緩存:
d. IO緩存:
使用具有緩存策略的輸入流,BufferedInputStream替代InputStream,BufferedReader替代Reader,BufferedReader替代BufferedInputStream.對(duì)文件、網(wǎng)絡(luò)IO皆適用。
e. 消息緩存:通過Handler的obtainMessage回收就的Message對(duì)象,減少M(fèi)essage對(duì)象的創(chuàng)建開銷
handler.sendMessage(handler.obtainMessage(1));
f. 通知欄notification緩存:下載中需要不斷改變通知欄進(jìn)度條狀態(tài),如果不斷新建Notification會(huì)導(dǎo)致通知欄很卡。這里我們可以使用最簡(jiǎn)單的緩存
Map<String, Notification> notificationMap = new HashMap<String, Notification>();如果notificationMap中不存在,則新建notification并且put into map.
(3). 其他
能創(chuàng)建基類解決問題就不用具體子類:除需要設(shè)置優(yōu)先級(jí)的線程使用new Thread創(chuàng)建外,其余線程創(chuàng)建使用new Runnable。因?yàn)樽宇悤?huì)有自己的屬性創(chuàng)建需要更多開銷。
控制最大并發(fā)數(shù)量:使用Java的Executors類,通過Executors.newFixedThreadPool(nThreads)控制線程池最大線程并發(fā)
對(duì)于http請(qǐng)求增加timeout 3. Layout優(yōu)化
性能優(yōu)化相關(guān)的一些標(biāo)簽 <viewStub/>,<merge/>和<include/> 可見: http://hexen.blog.51cto.com/1110171/820197
TextView屬性優(yōu)化:TextView的android:ellipsize=”marquee”跑馬燈效果極耗性能,具體原因還在深入源碼中
對(duì)于layout中的布局實(shí)際效果可使用hierarchyviewer查看
對(duì)于layout中多余的view以及不正確的標(biāo)簽可使用android lint查看
4. 數(shù)據(jù)庫優(yōu)化
主要包括sql優(yōu)化、建立索引、使用事務(wù)、讀寫表區(qū)分
(1). sql優(yōu)化
可參考http://database.51cto.com/art/200904/118526.htm
(2). 建立索引
使用CREATE INDEX mycolumn_index ON mytable (myclumn)語句在SQLiteOpenHelper子類的onCreate或onUpgrade函數(shù)創(chuàng)建索引,索引創(chuàng)建后對(duì)大數(shù)據(jù)量的查詢性能提升效果較明顯(3). 使用事務(wù)
事務(wù)不僅能保證批量操作一起完成或回滾,而且在大量插入、更新、查詢時(shí)減少程序和表的交互從而提高性能
5. 算法優(yōu)化
這個(gè)就是個(gè)博大精深的話題了,只介紹本應(yīng)用中使用的。
使用hashMap代替arrayList,時(shí)間復(fù)雜度降低一個(gè)數(shù)量級(jí)
6. 延遲執(zhí)行
對(duì)于很多耗時(shí)邏輯沒必要立即執(zhí)行,這時(shí)候我們可以將其延遲執(zhí)行。
線程延遲執(zhí)行 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
消息延遲發(fā)送 handler.sendMessageDelayed(handler.obtainMessage(0), 1000);
四、本程序性能調(diào)優(yōu)結(jié)果
1. ViewPager左右滑動(dòng)明顯卡頓
2. GridView上下滾動(dòng)明顯卡頓
(1). 去掉TextView的android:ellipsize=”marquee”
(2). 修改圖片緩存的最大線程數(shù),增加http timeout
(3). 修改設(shè)置app是否已安裝的狀態(tài),具體代碼修改如下:
3. 其他Activity返回ViewPager Activity較慢
定位:在onStart函數(shù)
解決:使用延遲策略,具體代碼修改如下:
解決:使用BufferedReader替代BufferedInputStream獲取時(shí)間從100ms降低到3ms,具體代碼修改如下:
總結(jié)
以上是生活随笔為你收集整理的Android性能调优实例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目成本管理名词解析
- 下一篇: Fresco图片加载+EventBus+