Android代碼優(yōu)化.doc_第1頁
Android代碼優(yōu)化.doc_第2頁
Android代碼優(yōu)化.doc_第3頁
Android代碼優(yōu)化.doc_第4頁
Android代碼優(yōu)化.doc_第5頁
免費(fèi)預(yù)覽已結(jié)束,剩余12頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

Android代碼優(yōu)化【轉(zhuǎn)】2010-08-20 23:40為性能設(shè)計(jì):1)避免創(chuàng)建對象對象的創(chuàng)建從來不是免費(fèi)的。雖然GC使得內(nèi)存申請代價不再高昂,但是申請總是比不申請來得昂貴。如果你在一個用戶接口循環(huán)中申請對象,你將會強(qiáng)行執(zhí)行周期性的GC,在用戶體驗(yàn)上出現(xiàn)一些小的“打嗝”,因此除非不得已,你應(yīng)該避免創(chuàng)建對象實(shí)例,下面是一些例子可以幫助理解:當(dāng)你在一組輸入數(shù)據(jù)中抽取字符串時,嘗試返回源數(shù)據(jù)的子串,而非創(chuàng)建一個副本。你將會創(chuàng)建一個新的String對象,但是它會和數(shù)據(jù)共享字符數(shù)組char。如果你有一個返回String的方法,而且你知道它的結(jié)果將會一直被追加到StringBuffer,改變你的簽名和實(shí)現(xiàn),使這個函數(shù)里面直接追加,避免創(chuàng)建臨時對象。 一個更激進(jìn)的主意是將多維數(shù)組切成與之平行的一維數(shù)組:一個int數(shù)組比Integer數(shù)組要好,但也有一個公認(rèn)的事實(shí)就是兩個平行的int數(shù)組要比一個(int,int)對象數(shù)組要高效很多。對于其它原始數(shù)據(jù)類型亦如是。如果你需要實(shí)現(xiàn)一個存儲一組對象(Foo,Bar)的容器,請記住兩個平等的Foo和Bar數(shù)組通常元比一個定制對象數(shù)組要好(當(dāng)然,對于此有個例外,就是當(dāng)你設(shè)計(jì)一個API供其它代碼訪問時;在那樣的情況下,通常最好是為保證API的正確性而犧牲一點(diǎn)速度。但是在你的內(nèi)部代碼,你應(yīng)該盡可能保持高效)。通常來說,避免創(chuàng)建臨時對象,如果你可以的話。更少的對象創(chuàng)建意味著更小頻率的GC,這對用戶體驗(yàn)有直接的影響。2)用Native方法當(dāng)處理字符串時,要毫不猶豫地使用諸如String.indexOf()、String.lastIndexOf()之類的專門方法,這些是典型的用C/C+代碼實(shí)現(xiàn)的方法,它們可以輕易地比實(shí)現(xiàn)同樣功能的Java循環(huán)快10-100倍。對此建議的一反面是調(diào)用一個native方法要比調(diào)用一個解析的方法,不要將native方法用于瑣碎的計(jì)算,如果可以避免的話。優(yōu)先使用Virtual而非Interface假如你有一個HashMap對象,你可以聲明它為一個HashMap或一個通用的Map:Map myMap1 = new HashMap();HashMap myMap2 = new HashMap();哪一個更好?一般的會說你該選擇Map,因?yàn)樗试S你改變其實(shí)現(xiàn),對于通常的編程來說這是對的,但是對于嵌入式系統(tǒng)來說這并不是太妙。通過接口的引用來調(diào)用一個方法要比通過一個具體類型的引用調(diào)用virtual方法花多2倍的時間。如果你已經(jīng)選擇了一個HashMap,因?yàn)樗眠m用你正在做的事情,那通過Map來調(diào)用就沒有什么價值了??紤]到IDE可以為你重構(gòu)代碼,用Map來調(diào)用就沒有太大價值了,即使你不知道你代碼將去向何方(但是,再一次的,公共的API是又是一個例外:好的API較少考慮性能)。3)優(yōu)先選擇static而非virtual如果你不必訪問一個對象的字段,使你的方法成為static方法。它可以被更快地調(diào)用,因?yàn)樗恍枰粋€虛擬方法表間接調(diào)用。同時它也是一個好的做法,因?yàn)閺姆椒ǖ暮灻梢钥闯稣{(diào)用這個方法不會改變對象的狀態(tài)。4)避免內(nèi)部的Getter/Setter在一些像C+的語言中,通常的做法是用getter(如:i=getCount())代替直接地訪問字段(i=mCount),在C+這是一個很好的習(xí)慣,因?yàn)榫幾g器通常能夠內(nèi)聯(lián)這個訪問,并且你需要限制或debug字段訪問,你可以在任何時候增加代碼。在Android,這是一個壞主意。虛擬方法調(diào)用代價是昂貴的,實(shí)例字段查找代價更高。沿用面一般向?qū)ο缶幊虒?shí)踐在公開接口中提供gettter和setter是合理的,但在一個類中你應(yīng)該直接訪問字段。Cache字段查找訪問對象字段要比訪問本地變量慢得多,如下面這段:for (int i = 0; i this.mCount; i+)dumpItem(this.mItemsi);應(yīng)該寫成這樣:int count = this.mCount;Item items = this.mItems;for (int i = 0; i count; i+)dumpItems(itemsi);(我們用一個顯式的”this”來表明這是一個成員變量。)有一個相似的指引就是,不要在for語句中的第二個從句中調(diào)用方法。例如下面這段代碼將會在每次迭代中都會執(zhí)行一次getCount(),這是一個巨大的浪費(fèi),你可以將它的值cache為一個int。for (int i = 0; i this.getCount(); i+) dumpItems(this.getItem(i);通常,如果你將要訪問一個實(shí)例字段多次,一個好的習(xí)慣就是創(chuàng)建一個臨時變量。例如:protected void drawHorizontalScrollBar(Canvas canvas, int width, int height) if (isHorizontalScrollBarEnabled() int size = mScrollBar.getSize(false); if (size = 0) size = mScrollBarSize; mScrollBar.setBounds(0, height size, width, height); mScrollBar.setParams( computeHorizontalScrollRange(), computeHorizontalScrollOffset(), computeHorizontalScrollExtent(), false); mScrollBar.draw(canvas); 這是對成員字段mScrollBar的四次分開查找,通過將mScrollBar緩存到本地變量,四次成員字段查找變成四次本地變量引用,這樣更為高效。同樣地,方法參數(shù)作為本地變量擁有相同的性能特征。聲明常量為final考慮在類開頭的如下聲明:static int intVal = 42;static String strVal = “Hello, world!”;編譯器產(chǎn)生一個叫的類初始化器方法,它在類首次使用時被執(zhí)行。這個方法將42存到intVal,并為intVal從類文件字符串常量表中抽出一個引用,當(dāng)這些值在后面被引用到時,它們以字段查找的方式被訪問。我們可以用final關(guān)鍵字改進(jìn)之:static final int intVal = 42;static final String strVal = “Hello, world!”;這個類不再需要一個方法,因?yàn)槌A看娴街苯佑蒝M處理的類文件靜態(tài)字段初始化器,代碼訪問intVal將會直接使用integer值42,而對intVal的訪問會用一個相對廉價的“字符串常量”指令來代替一個字段查找。聲明一個方法或類為final并不能直接獲得性能上的好處,但它確實(shí)能起到某些優(yōu)化作用。例如,假如編譯器知道一個”getter”不能被一個子類重寫,它能夠內(nèi)聯(lián)這個方法調(diào)用。你也可以將本地變量聲明為final,然而這并無真正意義上的性能提升。對于要地變量,只有在使代碼更清晰(或你不得不,如為了在匿名內(nèi)部類中使用)時使用final。小心使用增強(qiáng)的For循環(huán)語句增強(qiáng)的For語句可以用于實(shí)現(xiàn)了Iterable接口的Collection,對于這些對象,一個iterator被申請用來進(jìn)行接口調(diào)用hasNext()和next()。對于ArrayList,你最好直接遍歷它,但對于其它c(diǎn)ollections,增強(qiáng)的For循環(huán)語句將會等同于顯式的迭代用法。盡管如此,下面的代碼展示了增強(qiáng)的For語句的可為人接受的用法:public class Foo int mSplat; static Foo mArray = new Foo27; public static void zero() int sum = 0; for (int i = 0; i mArray.length; i+) sum += mArrayi.mSplat; public static void one() int sum = 0; Foo localArray = mArray; int len = localArray.length; for (int i = 0; i len; i+) sum += localArrayi.mSplat; public static void two() int sum = 0; for (Foo a: mArray) sum += a.mSplat; zero()在循環(huán)中每次迭代獲取靜態(tài)字段兩次計(jì)算數(shù)組長度一次。one()將所有東西存到本地變量,避免查找。two()用到了增強(qiáng)的For循環(huán)語句,由編譯器產(chǎn)生的代碼拷貝數(shù)組引用和數(shù)組長度到本地變量,使之成為一個遍歷數(shù)組元素的一個很好的選擇。它確實(shí)在主循環(huán)中產(chǎn)生了一個額外的本地載入/存儲,使得它比起one()有點(diǎn)慢并且長了bytes??傊鰪?qiáng)的For語句對于數(shù)組表現(xiàn)良好,但對iterable對象要小心使用,因?yàn)橛蓄~外的對象創(chuàng)建。避免Enum類型Enum非常方便,但不幸的是當(dāng)考慮到時間和速度時就讓人痛苦。例如這個:public class Foo public enum Shrubbery GROUND, CRAWLING, HANGING 將編譯成一個900byte的.class文件,在首次使用是時,類初始化器在代表每個被枚舉的值對象上激活方法。每個對象都有其靜態(tài)字段,并且整個集合就存儲在一個數(shù)組(一個稱為“$values”的靜態(tài)字段)上,對于僅僅的三個integer來說,那是太多的代碼和數(shù)據(jù)了。這個:Shrubbery shrub = Shrubbery.GROUND;導(dǎo)致了一次靜態(tài)字段查找。如果“GROUND”是一個static final int編譯器將會將它看作是一個常量并內(nèi)聯(lián)它。相反地,當(dāng)然,是運(yùn)用enum你可以得到一個更優(yōu)雅的API和一些編譯時的值檢查。因此,通常折衷的辦法是:為API,你應(yīng)該千方百計(jì)地使用enum,但是當(dāng)考慮到性能時嘗試避免使用它。利用內(nèi)部類使用包作用方域考慮下面的類定義:public class Foo private int mValue; public void run() Inner in = new Inner(); mValue = 27; in.stuff(); private void doStuff(int value) System.out.println(“Value is ” + value); private class Inner void stuff() Foo.this.doStuff(Foo.this.mValue); 在這里我們要特別指出的是這里定義了一個內(nèi)部類(Foo$Inner),它可以直接訪問外部類的私有方法和私有實(shí)例字段,這是合法的,代碼的執(zhí)行的結(jié)果是如預(yù)期般的“Value is 27”。問題在于,F(xiàn)oo$Inner是一個完全獨(dú)立的類,這使得直接訪問其私有方法是非法的,為了架起橋梁,編譯器會產(chǎn)生如下兩個虛擬方法/*package*/ static int Foo.access$100(Foo foo) return foo.mValue;/*package*/ static void Foo.access$200(Foo foo, int value) foo.doStuff(value);當(dāng)內(nèi)部類代碼需要訪問外部類的mValue變量或激活doStuff方法時就會調(diào)用這些方法。這就意味著上面的代碼清楚表明了你是通過訪問器來訪問成員字段的,而非直接訪問。前面我們討論過訪問器是比直接訪問是要慢的,所以這是一個由于某種特定語言方言所導(dǎo)致的隱性性能打擊。我們可以通過聲明由內(nèi)部類訪問的字段和方法為具有包作用域而非私有作用域來解決這個問題。這樣運(yùn)行得更快并且移除了額外產(chǎn)生的方法(不幸的是,這也意味著這些字段可以被同包下的其它類所訪問,這個是違反了使所有的字段成為私有的標(biāo)準(zhǔn)OO做法的,再一次的,如果你是在設(shè)計(jì)一個公共的API的話,你可能要慎重地考慮這一優(yōu)化策略)。)避免使用Float類型在Pentium CPU發(fā)布之前,對于游戲作者來說做很多整型計(jì)算是很正常的事。有了Pentium之后,浮點(diǎn)計(jì)算聯(lián)合處理器成了內(nèi)置功能,你的游戲通過交錯整型和浮點(diǎn)操作比只有整型計(jì)算時運(yùn)行起來要快得多。在桌面系統(tǒng)上通常的可以自由的使用浮點(diǎn)數(shù)。不幸的是,嵌入式處理器很少具有硬件浮點(diǎn)支持,所以所有的”float”和”double”操作都是在軟件上進(jìn)行。某些基本的浮點(diǎn)操作可能會花費(fèi)數(shù)微秒。還有,甚至對于整型數(shù),一些芯片支持硬件乘法但缺少硬件除法,在這種情況下,整型除法和取模運(yùn)算是在軟件上執(zhí)行的如果你是在設(shè)計(jì)一個哈希表或做很多數(shù)學(xué)運(yùn)算這就是你需要考慮的事情。為響應(yīng)靈敏性設(shè)計(jì)代碼可能通過各種性能測試,但是當(dāng)用戶使用時還是會需要漫長的等待,這些就是那種響應(yīng)不夠靈敏的應(yīng)用它們反應(yīng)遲鈍,掛起或凍住周期很長,或者要花很長時間來處理輸入。在Android上,系統(tǒng)通過向用戶顯示一個稱為應(yīng)用無響應(yīng)(ANR:Application Not Responding)的對話框來防止在一段時間內(nèi)響應(yīng)不夠快。用戶可以選擇讓應(yīng)用繼續(xù),但是用戶并不會想要每次都來處理這個對話框。因此應(yīng)把你的應(yīng)用設(shè)計(jì)得響應(yīng)靈敏,使得系統(tǒng)不必顯示ANR給用戶。通常地,當(dāng)不能響應(yīng)用戶輸入時系統(tǒng)顯示一個ANR。例如,如果一個應(yīng)用在IO操作(經(jīng)常是網(wǎng)絡(luò)訪問)上阻塞了,那么主應(yīng)用線程就會無法處理正在進(jìn)行的用戶輸入事件。經(jīng)過一段時間,系統(tǒng)認(rèn)為應(yīng)用已經(jīng)掛起,向用戶顯示一個ANR,讓用戶可以選擇關(guān)閉。相同地,如果你的應(yīng)用花太多的時間在構(gòu)建詳細(xì)的內(nèi)存結(jié)構(gòu)上,又或者在計(jì)算游戲的下一個動作上,系統(tǒng)會認(rèn)為你的應(yīng)用已經(jīng)掛起。用上面的技術(shù)來保證這些計(jì)算是高效的一直都是很重要的,但是即使是最高效的代碼運(yùn)行也是需要花費(fèi)時間的。在這兩種情況下,解決的辦法通常就是創(chuàng)建一個子線程,在這個子線程上做你的大部分工作。這樣讓你的主線程(驅(qū)動用戶接口事件循環(huán))保持運(yùn)行,并讓你的代碼免于被系統(tǒng)認(rèn)為已經(jīng)凍住。因?yàn)檫@樣的線程化通常都是在類級別上來完成的,所以你可以認(rèn)為響應(yīng)性能問題是一個類問題(與上面描述的方法級別的性能問題)。這個文檔討論了Android系統(tǒng)是如何決定一個應(yīng)用沒有響應(yīng)的,并提供了指引來保障你的應(yīng)用是響應(yīng)靈敏的。1)是什么引發(fā)了ANR?在Android系統(tǒng)上,應(yīng)用的響應(yīng)靈敏性由Activity Manager和Window Manager system services所監(jiān)控,當(dāng)它監(jiān)測到如下的其中一個條件時,Android就會為特定的應(yīng)用顯示一個ANR:5秒內(nèi)對輸入事件無響應(yīng)。一個BroadCastReceiver在10秒內(nèi)沒有執(zhí)行完畢。怎樣避免ANR?考慮到上面對ANR的定義,讓我們來研究一下這是為什么會發(fā)生以及怎樣最好的組織你的應(yīng)用以避免ANR。Android應(yīng)用正常是運(yùn)行在一個單獨(dú)的(如main)線程中的,這就意味著在你應(yīng)用主線程中正在做的需要花很長時間來完成的事情都能夠激活A(yù)NR對話框。因?yàn)槟愕膽?yīng)用并沒有給自己一個機(jī)會來處理輸入事件或Intent廣播。因此任何運(yùn)行在主線程中的方法應(yīng)該做盡可能少的事情。特別地Activitiy在關(guān)鍵生命周期方法中如onCreate()和onResume()應(yīng)當(dāng)做盡可能少的設(shè)置。潛在地的耗時長的操作(如網(wǎng)絡(luò)或數(shù)據(jù)庫操作,或高耗費(fèi)數(shù)學(xué)計(jì)算如改變位圖大?。?yīng)該在子線程里面完成(或以數(shù)據(jù)庫操作為例,可以通過異步請求)。盡管如此,這并不是說當(dāng)?shù)却泳€程完成的過程中你的主線程必須被阻塞你不必調(diào)用Thread.wait()或Thread.sleep(),恰恰相反,你的主線程應(yīng)該為子線程提供一個Handler,以便子線程完成時可以提交回給主線程。以這種方式來設(shè)計(jì)你的應(yīng)用,將會允許你的主線程一直可以響應(yīng)輸入,以避免由5秒鐘的輸入事件超時導(dǎo)致的ANR對話。這些做法同樣應(yīng)該被其它任何顯示UI的線程所效仿,因?yàn)樗鼈儗儆谕瑯宇愋偷某瑫r。IntentReciever執(zhí)行時間的特定限制限制了它們應(yīng)該做什么:在后臺執(zhí)行的一些瑣碎的工作如保存設(shè)置或注冊通知。至于其它在主線程里被調(diào)用的方法,在BroadcastReceiver中,應(yīng)用應(yīng)該避免潛在的長耗時操作或計(jì)算,而是應(yīng)該用子線程來完成密集任務(wù)(因?yàn)锽roadcastReceiver的生命周期是短暫的)。對Intent broadcast作出響應(yīng),你的應(yīng)用應(yīng)該啟動一個Service來執(zhí)行長耗時的動作。同樣,你也應(yīng)該避免從Intent Receiver中啟動Activity,因?yàn)樗鼤a(chǎn)生一個新的屏,偷走任何用戶正在運(yùn)行的應(yīng)用的焦點(diǎn)。對Intent broadcast作出的響應(yīng),假如你的應(yīng)用需要向用戶顯示什么東西,應(yīng)該用Notification Manager來完成。增強(qiáng)響應(yīng)靈敏性通常,在一個應(yīng)用中,100到200微秒是一個讓用戶感覺到阻滯的閾值,因此這里有些小技巧讓你用來使你的應(yīng)用看起來響應(yīng)更靈敏。如果你的應(yīng)用正在后臺對用戶輸入作出響應(yīng),顯示正在進(jìn)行的進(jìn)度(ProgressBar和ProgressDialog對此很有用)。特別是對于游戲,在子線程中做移動的計(jì)算。如果你的應(yīng)用有一個耗時的初始化過程,考慮用閃屏或盡可能快地渲染主界面并異步地填充信息。在這兩種情況下你都應(yīng)該表明進(jìn)度正在進(jìn)行,以免用戶覺得你的應(yīng)用被凍住了。為無縫設(shè)計(jì):即使你的應(yīng)用是快速且響應(yīng)靈敏的,一些設(shè)計(jì)仍然能句對用戶造成問題因?yàn)榕c其它應(yīng)用未計(jì)劃的交互或者對話,意外的數(shù)據(jù)丟失,無意識的阻塞等等。為了避免這些問題,有助于理解你的應(yīng)用運(yùn)行的環(huán)境和可以影響你的應(yīng)用的系統(tǒng)交互。總之,你應(yīng)該倔盡全力地開發(fā)一個與系統(tǒng)和其它應(yīng)用無縫交互的應(yīng)用。一個常見的無縫問題就是一個應(yīng)用的后臺進(jìn)程(如service或broadcast receiver)對某事件作出響應(yīng)而彈出對話框,這看起來仿佛并無大礙,特別是當(dāng)你在模擬器上單獨(dú)地構(gòu)建和測試你的應(yīng)用時。然而,當(dāng)你的應(yīng)用在真正的設(shè)備上運(yùn)行,后臺線程顯示對話框時,你的應(yīng)用當(dāng)時可能沒有獲得用戶焦點(diǎn)。這就會出現(xiàn)你的應(yīng)用會在活動的應(yīng)用后面顯示對話框,或者從當(dāng)前應(yīng)用中獲得焦點(diǎn)并顯示對話框的情況,而管論當(dāng)時用戶正在做什么(如正在打電話等)。那樣的行為可能對你的應(yīng)用或用戶不起作用。為了避免這些問題,你的應(yīng)用應(yīng)該利用適當(dāng)?shù)南到y(tǒng)資源Notification類,來通知用戶。利用通知,你的應(yīng)用可以通過在狀態(tài)條上顯示一個圖標(biāo)來通知用戶事件已經(jīng)發(fā)生,而非獲得焦點(diǎn)和打斷用戶。另外一個無縫問題的例子就是,Activity由于未能正確實(shí)現(xiàn)onPause()及其它生命周期方法而無意中丟失了狀態(tài)或用戶數(shù)據(jù)。又或者,你的應(yīng)用要暴露供其它應(yīng)用使用的數(shù)據(jù),你應(yīng)該通過ContentProvider來實(shí)現(xiàn),而非通過一個全世界都可讀的原始文件或數(shù)據(jù)庫。這些例子的共同特點(diǎn)就是,它們都是關(guān)于如何跟系統(tǒng)和其它應(yīng)用協(xié)作得更好,Android系統(tǒng)的設(shè)計(jì)就是將所有的應(yīng)用看作是一個松散耦合的組件聯(lián)邦,不是一堆墨盒代碼。這就使你作為一個開發(fā)者可以將整個系統(tǒng)視為只是一個更大一點(diǎn)的組件聯(lián)邦。這樣有得于你將應(yīng)用與其它應(yīng)用清晰和無縫的集成,所以作為回報,你應(yīng)該更好的設(shè)計(jì)你的代碼。這個文檔討論了常見的無縫集成問題和怎樣去避免它們。它包含了如下主題:別丟棄數(shù)據(jù)一定要記住Android是一個移動平臺??雌饋砗茱@然,但是記住這個事實(shí)很重要,就是任何Activity(如”正在打進(jìn)來的電話”應(yīng)用)在任何時候都有可能彈出來覆蓋你的Activity,這會激活onSaveInstanceState()和onPause()方法,并導(dǎo)致你的應(yīng)用被殺死。如果當(dāng)其它Activity出現(xiàn)時,用戶正好在你的應(yīng)用上編輯數(shù)據(jù),你的應(yīng)用被殺死的同時那些數(shù)據(jù)也很可能會丟失。當(dāng)然了,除非你先保存了進(jìn)行中的工作?!癆ndroid方式”是這么做的:能接收和編輯用戶輸入的應(yīng)用需要重寫onSaveInstanceState()方法并以恰當(dāng)?shù)姆绞奖4嫠鼈兊臓顟B(tài),當(dāng)用戶重新訪問應(yīng)用時,就能重新獲得數(shù)據(jù)。一個運(yùn)用這個行為經(jīng)典的例子就是郵件應(yīng)用,當(dāng)用戶正在撰寫郵件時另一人Activity開始了,應(yīng)用應(yīng)該將正在編輯的郵件保存為草稿。不要暴露原始數(shù)據(jù)如果你不想穿著內(nèi)衣在大街上散步,同樣你的數(shù)據(jù)也不應(yīng)如此。盡管可能暴露某些應(yīng)用可以方便其它應(yīng)用讀取,但這通常不是最好的主意。暴露原始數(shù)據(jù)要求其它的應(yīng)用能夠理解你的數(shù)據(jù)格式;如果你改變了格式,你將會破壞其它沒有同時更新的應(yīng)用。“Android方式”就是創(chuàng)建一個ContentProvider通過一個清晰的、深思熟慮的、可維護(hù)的API來暴露你的數(shù)據(jù)給其它應(yīng)用。使用ContentProvider就像一個Java接口來分離和組件化兩段緊密耦合的代碼,這就意味著你能夠修改你數(shù)據(jù)的內(nèi)部格式而不用修改由ContentProvider暴露的接口,這樣就不會影響其它應(yīng)用。別打斷用戶如果能確定一個用戶是帶有目的性的運(yùn)行一個應(yīng)用才是安全的。那就是為什么你除非是直接響應(yīng)當(dāng)前活動的用戶輸入,不然就要避免產(chǎn)生Activity的原因。那就是說,不要從后臺運(yùn)行的BroadcastReceiver和Service中調(diào)用startActivity()。如果這樣做將會打斷任何正在運(yùn)行的應(yīng)用,并使用戶惱怒。甚至你的Activity可能成為一個“擊鍵強(qiáng)盜”接收一些用戶正在為上一個Activity提供的輸入,視乎你的應(yīng)用所做的,這是這可能是個壞消息。取代直接從后臺直接產(chǎn)生Activity UIs,你應(yīng)該用NotificationManager來設(shè)置通知,這將會出現(xiàn)在狀態(tài)條上,當(dāng)用戶空閑時可以點(diǎn)擊它們來看你的應(yīng)用向他們顯示了什么。(注意,當(dāng)你的Activity已經(jīng)在前臺時所有這些都沒適用:這時,對于輸入的響應(yīng),用戶期望看到你的下一個Activity。)有太多事要做?在一個線程里做如果你的應(yīng)用需要做一個代價高昂或長耗時的計(jì)算,你可能要將它移到一個線程里。這個將會防止顯示“Application Not Responding”對話框給用戶,最終導(dǎo)致你的應(yīng)用完全終止。默認(rèn)地,在一個Activity中的代碼和其所有的View運(yùn)行在同一個線程上。這與處理UI事件的線程是同一個。例如,當(dāng)一個鍵被按下時,一個key-down事件被添加到Activity主線程的隊(duì)列。事件處理系統(tǒng)需要很快地讓這個事件出列并處理這個事件。不然,系統(tǒng)數(shù)秒后將會認(rèn)為應(yīng)用已經(jīng)掛起并替用戶殺死這個應(yīng)用。如果你有長耗時的代碼,讓它在你的Activity上內(nèi)聯(lián)運(yùn)行將會在使它運(yùn)行在事件處理線程上,這很大程度上阻塞了了事件處理句柄。這會延緩輸入處理并導(dǎo)致ANR對話框。為了避免之,將你的計(jì)算移到一個線程中。在為響應(yīng)靈敏性設(shè)計(jì)中已經(jīng)討論了如何做。5)不要過載一個單一的Activity屏任何值得使用的應(yīng)用都可能會有幾個不同的屏幕。當(dāng)設(shè)計(jì)你的UI屏幕時,請一定要運(yùn)用多個Activity對象實(shí)例。依賴于你的開發(fā)背景,你可能像解釋某些類似Java Applet的東西一樣來解釋一個Activity,Activity是你應(yīng)用的入口點(diǎn)。然而,那并不是準(zhǔn)確:一個pplet的子類是一個Javapplet的單一入口點(diǎn),而一個Activity應(yīng)該被看作一個潛在的進(jìn)入你的應(yīng)用的多個入口點(diǎn)。在你的”main”Activity和任何其它你可能有的Activity之間的唯一不同就是,那“miain”Activity碰巧是那個唯一在你的AndroidManifest.xml文件中對“ent.action.MAIN”動作有興趣的一個而已。所以,當(dāng)設(shè)計(jì)你的應(yīng)用時,把你的應(yīng)用看成一個Activity對象的聯(lián)邦。從長遠(yuǎn)來看,這會使得你的代碼更具可維護(hù)性。6)擴(kuò)展系統(tǒng)主題當(dāng)提到用戶接口的觀感時,協(xié)調(diào)是很重要的。

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論