基于Android平臺(tái)智能手機(jī)報(bào)系統(tǒng)的設(shè)計(jì)與開發(fā)

前言:

本文寫于2012年11月,轉(zhuǎn)眼間7年的時(shí)間過去了,最近翻箱倒柜找出來了,看看7年之前寫的代碼和文章,簡直不敢直視,哈哈哈,也沒有修改直接分享出來,以示紀(jì)念。本文出自門心叼龍的博客,轉(zhuǎn)載請(qǐng)注明出處。屬于原創(chuàng)類容,侵權(quán)必究。 https://blog.csdn.net/geduo_83/article/details/85858394

**1 ******研究意義****

中國互聯(lián)網(wǎng)發(fā)展迅速,據(jù)中國互聯(lián)網(wǎng)絡(luò)信息中心(CNNIC)發(fā)布的統(tǒng)計(jì)報(bào)告顯示,截至2011年底,中國網(wǎng)民規(guī)模突破5億,達(dá)到5.13億,全年新增網(wǎng)民5580萬,中國手機(jī)網(wǎng)民規(guī)模達(dá)到3.56億,同比增長17.5%。隨著智能手機(jī)的普及,龐大的智能手機(jī)網(wǎng)民規(guī)模為移動(dòng)互聯(lián)網(wǎng)應(yīng)用的爆發(fā)提供了基礎(chǔ),各大互聯(lián)網(wǎng)服務(wù)商也開始紛紛布局移動(dòng)互聯(lián)網(wǎng),而激烈的競爭必將催生能夠滿足細(xì)分人群需求的創(chuàng)新應(yīng)用,并進(jìn)一步推動(dòng)手機(jī)網(wǎng)民進(jìn)入下一輪高速增長周期。

移動(dòng)互聯(lián)網(wǎng)現(xiàn)在已經(jīng)成為人們生活不可或缺的一部分,手機(jī)閱讀報(bào)紙是依托手機(jī)媒介,由報(bào)紙和網(wǎng)絡(luò)運(yùn)營商聯(lián)手搭建的信息傳播平臺(tái),用戶可通過手機(jī)瀏覽到當(dāng)天發(fā)生的新聞,手機(jī)閱讀方便,快捷,隨時(shí)隨地,為傳統(tǒng)的互聯(lián)網(wǎng)應(yīng)用提供了新的發(fā)展空間和可持續(xù)發(fā)展的新商業(yè)模式,促進(jìn)了移動(dòng)網(wǎng)絡(luò)寬帶化的深入發(fā)展。通過本系統(tǒng)可以在智能手機(jī)上“原汁原味”直接閱讀報(bào)紙版面和新聞,便捷和“原汁原味”,這正是智能手機(jī)報(bào)系統(tǒng)最有價(jià)值的地方。

**2 ******NativeApp和WebApp優(yōu)缺點(diǎn)分析****

在智能手機(jī)上所運(yùn)行的應(yīng)用程序,根據(jù)開發(fā)方式的不同分為兩種,一種是Native App,另外一種是Web App

Web App無需安裝,對(duì)設(shè)備碎片化的適應(yīng)能力優(yōu)于App,它只需要通過XHTML、CSS和JavaScript就可以在任意移動(dòng)瀏覽器中執(zhí)行。開發(fā)成本低、適配多種移動(dòng)設(shè)備成本低、跨平臺(tái)和終端、迭代更新容易、無需安裝成本,但是不支持離線模式、消息推送不夠及時(shí)、調(diào)用本地文件系統(tǒng)的能力弱。

Native App因?yàn)槲挥谄脚_(tái)層上方,向下訪問和兼容的能力會(huì)比較好一些,提供最佳的用戶體驗(yàn),最優(yōu)質(zhì)的用戶界面,最華麗的交互、針對(duì)不同平臺(tái)提供不同體驗(yàn)、可節(jié)省帶寬成本、可訪問本地資源,但是移植到不同平臺(tái)上比較麻煩、維持多個(gè)版本的成本比較高,App的開發(fā)成本要高很多,維持多個(gè)版本的更新升級(jí)比較麻煩

智能手機(jī)報(bào)的核心功能是報(bào)紙閱讀,需要上下翻頁,為了提供最佳的用戶體驗(yàn),和優(yōu)質(zhì)的用戶界面,本系統(tǒng)采用Native App方式開發(fā)

**3 ******Android的架構(gòu)分析****

Android是一個(gè)移動(dòng)設(shè)備的軟件平臺(tái),是由Linux+Java構(gòu)成的開源軟件,它提供包括SDK、Apps、Middleware、Linux Kernel四個(gè)部分在內(nèi)的全套手機(jī)軟件方案。它開放了基于Linux內(nèi)核以上的開發(fā)工具,從而保證了內(nèi)容的可移植性和多樣性。Android平臺(tái)為我們開發(fā)應(yīng)用程序提供了一套很好的框架,我們可以在這個(gè)平臺(tái)的基礎(chǔ)上開發(fā)不同的應(yīng)用程序,也可以開發(fā)新的組件供應(yīng)用程序調(diào)用。

**3.1 ******Android架構(gòu)****

Android的架構(gòu)是Linux內(nèi)核、C/C++函數(shù)庫、Dalvik虛擬機(jī)、應(yīng)用框架以及關(guān)鍵應(yīng)用程序構(gòu)成的,如圖2-1。通過編譯基于框架的應(yīng)用程序可以降低開發(fā)負(fù)荷。應(yīng)用軟件原則上是在Dalvik VM上運(yùn)行的。

第一層:Linux 內(nèi)核,Display Rriver、Camera Driver、Flash Memory Driver、Wifi Driver它是整個(gè)Android系統(tǒng)最基礎(chǔ),最核心的部分

第二層:系統(tǒng)運(yùn)行庫(程序庫和運(yùn)行庫),主要包括SQLite(一個(gè)小型的關(guān)系型數(shù)據(jù)庫),WebKit(一個(gè)開源的瀏覽器),OpenGL(3G開發(fā)API),同時(shí)在這一層還有個(gè)Android Runtime(android運(yùn)行環(huán)境),主要包括Core Libraries(Java開發(fā)中常用的一些資源包)和Android運(yùn)行虛擬機(jī)

第三層:應(yīng)用程序框架層(Application FrameWork),如:ActivtiyManager,ContentProvider,Window Manager(就是我們?cè)陂_發(fā)Android應(yīng)用程序,所需要的的一些框架)

第四層:應(yīng)用程序?qū)樱ˋpplication),如:Home,Contacts、phone等等

**3.2 ******Android應(yīng)用的構(gòu)成和工作機(jī)制****

對(duì)于一個(gè)Android應(yīng)用程序來說,是由Activity、 BroadcastReceiver 、Service、ContentProvider四部分組成,但并不是每一個(gè)Android應(yīng)用程序都必須由這四部分組成。在應(yīng)用程序中使用時(shí),需要在配置文件AndroidMainfest.xml中進(jìn)行配置。這個(gè)配置文件是每個(gè)Android應(yīng)用程序所必需的,用于定義應(yīng)用程序的組件、組件的功能以及必要條件等。

**3.2.1 ******Activity****

Activity是構(gòu)成應(yīng)用程序中最重要的構(gòu)造塊, 在Android應(yīng)用程序中,幾乎都是通過Activity來與用戶進(jìn)行交互,所以Activity主要負(fù)責(zé)的就是創(chuàng)建與用戶進(jìn)行交互的顯示窗口,你可以在這些窗口里通過調(diào)用setContentView(View)方法來顯示你自己的用戶界面。

活動(dòng)生命周期

活動(dòng)(Activity)在系統(tǒng)中以活動(dòng)棧的形式進(jìn)行管理。當(dāng)一個(gè)新的活動(dòng)啟動(dòng)后,被放到了棧項(xiàng),成為了運(yùn)行活動(dòng),而新活動(dòng)之前的活動(dòng)在活動(dòng)棧里總位于新活動(dòng)之下,直到新的活動(dòng)退出才重新回到前臺(tái)。

(1)活動(dòng)的整個(gè)生命期:從首次調(diào)用onCreate(Bundle)開始,到最終調(diào)用onDestroyO結(jié)束。在onCreate()中進(jìn)行所有初始化,在onDestroyO時(shí)進(jìn)行清理工作,釋放資源。

(2)活動(dòng)的可見生命期:從調(diào)用onStart()開始,到onStop()被調(diào)用為止。在這段時(shí)間內(nèi),即使活動(dòng)不與用戶進(jìn)行交互,用戶也可以在屏幕上看到它。在這兩個(gè)方法調(diào)用之間,可以維護(hù)活動(dòng)顯示給用戶的資源。onStart()和onStop()方法可以多次調(diào)用,因?yàn)榛顒?dòng)隨時(shí)可以在可見和隱藏之間進(jìn)行轉(zhuǎn)換。

(3)活動(dòng)的后臺(tái)生命期:從調(diào)用onResume()開始,到onPause()被調(diào)用為止。在這段時(shí)間內(nèi)活動(dòng)處于其它所有活動(dòng)之前,并與用戶進(jìn)行交互。一個(gè)活動(dòng)可以不斷在resumed狀態(tài)和paused狀態(tài)之間變換[4]。

活動(dòng)之間的切換

Android使用了Intent類來實(shí)現(xiàn)活動(dòng)之間的切換工作。Intent負(fù)責(zé)對(duì)應(yīng)用中一次操作的動(dòng)作、動(dòng)作涉及的數(shù)據(jù)和附加數(shù)據(jù)進(jìn)行描述。根據(jù)Intent的描述,負(fù)責(zé)找到對(duì)應(yīng)的組件,將Intent傳遞給調(diào)用的組件并完成組件的調(diào)用。因此,Intent起著一種媒體中介的作用,專門提供組件互相調(diào)用的相關(guān)信息,實(shí)現(xiàn)調(diào)用者與被調(diào)用者之間的解耦。在應(yīng)用中,我們可以以兩種形式來使用Intent:直接Intent,指定了component屬性的Intent,通過指定具體的組件類,通知應(yīng)用啟動(dòng)對(duì)應(yīng)的組件。間接Intent,沒有指定comonent屬性的Intent,則需要包含足夠的信息,這樣系統(tǒng)才能根據(jù)這些信息,在所有的可用組件中,確定滿足此Intent的組件。

**3.2.2 ******BroadcastReceiver****

BroadcastReceiver是用于對(duì)外部事件的響應(yīng),當(dāng)外部事件發(fā)生時(shí),會(huì)使用NotificationManager通知用戶。當(dāng)一個(gè)BroadcastReceiver被觸發(fā)時(shí),系統(tǒng)會(huì)在需要的時(shí)候啟動(dòng)對(duì)應(yīng)的應(yīng)用程序。如在本系統(tǒng)中,當(dāng)用戶正在其它界面進(jìn)行操作時(shí),有好友發(fā)送消息過來,就會(huì)以通知的形式發(fā)送到當(dāng)前界面的正上方來通知用戶。各種應(yīng)用還可以通過使用Context.broadcastIntent()將它們的BroadcastReceiver廣播給其它的應(yīng)用程序,實(shí)現(xiàn)應(yīng)用之間的通訊。

**3.2.3 ******Service****

Service是提供連續(xù)信息的應(yīng)用程序。它是運(yùn)行于應(yīng)用程序后臺(tái)的服務(wù),在用戶進(jìn)行其它活動(dòng)的時(shí)候,這個(gè)服務(wù)將一直運(yùn)行在基于Android平臺(tái)的即時(shí)通訊統(tǒng)的研究與實(shí)現(xiàn)后臺(tái)直到用戶停止該服務(wù)或服務(wù)運(yùn)行結(jié)束。本系統(tǒng)客戶端擴(kuò)展功能的音樂播放就是采用Service來進(jìn)行設(shè)計(jì)和開發(fā)的,使用戶可以邊聊天邊聽音樂。

**3.2.4 ******ContentProvider****

Content Provider應(yīng)用程序能夠?qū)⑺鼈兊臄?shù)據(jù)保存到文件、SQL數(shù)據(jù)庫和其它的存儲(chǔ)設(shè)備中。當(dāng)應(yīng)用程序需要使用存儲(chǔ)設(shè)備中的數(shù)據(jù)時(shí),可以使用Content Provider來完成。使用Content Provider能夠靈活的替換底層使用的存儲(chǔ)設(shè)備,使開發(fā)者可以專著于應(yīng)用邏輯的開發(fā),不用考慮底層存儲(chǔ)設(shè)備的細(xì)節(jié),從而使應(yīng)用系統(tǒng)具有良好的數(shù)據(jù)

**4 ****** 需求分析****

**4.1 ******業(yè)務(wù)流程圖****

[圖片上傳失敗...(image-36e2dd-1555414018806)]

image.gif

?
image
image.gif

?

**4.2 ******主要功能****

[圖片上傳失敗...(image-ee7c3b-1555414018806)]

image.gif

?
image
image.gif

?

**5 ******系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)****

**5.1 ******相關(guān)技術(shù)****

**5.1.1 ******Http通信****

HttpURLConnection接口

首先需要明確的是,Http通信中的POST和GET請(qǐng)求方式的不同。GET可以獲得靜態(tài)頁面,也可以把參數(shù)放在URL字符串后面,傳遞給服務(wù)器。而POST方法的參數(shù)是放在Http請(qǐng)求中。因此,在編程之前,應(yīng)當(dāng)首先明確使用的請(qǐng)求方法,然后再根據(jù)所使用的方式選擇相應(yīng)的編程方式。

HttpURLConnection是繼承于URLConnection類,二者都是抽象類。其對(duì)象主要通過URL的openConnection方法獲得。創(chuàng)建方法如下代碼所示:
URL url = new URL("http://....");  

HttpURLConnection urlConn=(HttpURLConnection)url.openConnection();
image.gif

**5.1.2 ******xml解析****

<u><u>Android</u></u>平臺(tái)上可以使用Simple API for XML(SAX)、Document Object Model(DOM)和Android附帶的pull解析器解析XML文件。

(1)使用SAX讀取XML文件

SAX是一個(gè)解析速度快并且占用內(nèi)存少的XML解析器,非常適合用于Android等移動(dòng)設(shè)備。SAX解析XML文件采用的是事件驅(qū)動(dòng),也就是說,它并不需要解析完整個(gè)文檔,在按內(nèi)容順序解析文檔的過程中,SAX會(huì)判斷當(dāng)前讀到的字符是否合法XML語法中的某部分,如果符合就會(huì)觸發(fā)事件。所謂事件,其實(shí)就是一些回調(diào)(callback)方法,這些方法(事件)定義在ContentHandler接口。

下面是一些ContentHandler接口常用的方法:

startDocument()當(dāng)遇到文檔的開頭的時(shí)候,調(diào)用這個(gè)方法,可以在其中做一些預(yù)處理的工作。

endDocument()和上面的方法相對(duì)應(yīng),當(dāng)文檔結(jié)束的時(shí)候,調(diào)用這個(gè)方法,可以在其中做一些善后的工作。
startElement(String namespaceURI, String localName, String qName, Attributes atts)當(dāng)讀到一個(gè)開始標(biāo)簽的時(shí)候,會(huì)觸發(fā)這個(gè)方法。namespaceURI就是命名空間,localName是不帶命名空間前綴的標(biāo)簽名,qName是帶命名空間前綴的標(biāo)簽名。通過atts可以得到所有的屬性名和相應(yīng)的值。要注意的是SAX中一個(gè)重要的特點(diǎn)就是它的流式處理,當(dāng)遇到一個(gè)標(biāo)簽的時(shí)候,它并不會(huì)紀(jì)錄下以前所碰到的標(biāo)簽,也就是說,在startElement()方法中,所有你所知道的信息,就是標(biāo)簽的名字和屬性,至于標(biāo)簽的嵌套結(jié)構(gòu),上層標(biāo)簽的名字,是否有子元屬等等其它與結(jié)構(gòu)相關(guān)的信息,都是不得而知的,都需要你的程序來完成。這使得SAX在編程處理上沒有DOM來得那么方便。
endElement(String uri, String localName, String name)這個(gè)方法和上面的方法相對(duì)應(yīng),在遇到結(jié)束標(biāo)簽的時(shí)候,調(diào)用這個(gè)方法。
characters(char[] ch, int start, int length)這個(gè)方法用來處理在XML文件中讀到的內(nèi)容,第一個(gè)參數(shù)用于存放文件的內(nèi)容,后面兩個(gè)參數(shù)是讀到的字符串在這個(gè)數(shù)組中的起始位置和長度,使用new String(ch,start,length)就可以獲取內(nèi)容。

(2)使用DOM讀取XML文件

除了可以使用 SAX解析XML文件,大家也可以使用熟悉的DOM來解析XML文件。 DOM解析XML文件時(shí),會(huì)將XML文件的所有內(nèi)容讀取到內(nèi)存中,然后允許您使用DOM API遍歷XML樹、檢索所需的數(shù)據(jù)。使用DOM操作XML的代碼看起來比較直觀,并且,在某些方面比基于SAX的實(shí)現(xiàn)更加簡單。但是,因?yàn)镈OM需要將XML文件的所有內(nèi)容讀取到內(nèi)存中,所以內(nèi)存的消耗比較大,特別對(duì)于運(yùn)行Android的移動(dòng)設(shè)備來說,因?yàn)樵O(shè)備的資源比較寶貴,所以建議還是采用SAX來解析XML文件,當(dāng)然,如果XML文件的內(nèi)容比較小采用DOM是可行的。

(3)使用Pull解析器讀取XML文件

除了可以使用 SAX和DOM解析XML文件,大家也可以使用Android內(nèi)置的Pull解析器解析XML文件。 Pull解析器的運(yùn)行方式與 SAX 解析器相似。它提供了類似的事件,如:開始元素和結(jié)束元素事件,使用parser.next()可以進(jìn)入下一個(gè)元素并觸發(fā)相應(yīng)事件。事件將作為數(shù)值代碼被發(fā)送,因此可以使用一個(gè)switch對(duì)感興趣的事件進(jìn)行處理。當(dāng)元素開始解析時(shí),調(diào)用parser.nextText()方法可以獲取下一個(gè)Text類型元素的值

**5.1.3 ******廣播機(jī)制****

BroadcastReceiver:他主要是實(shí)現(xiàn)了不同的應(yīng)用程序之間數(shù)據(jù)的異步接收,其本質(zhì)是一個(gè)事件監(jiān)聽器,用于監(jiān)聽系統(tǒng)全局的廣播消息

1.概念:

1.1 Broadcast:是一種廣泛運(yùn)用的在應(yīng)用程序之間傳輸信息的機(jī)制

1.2 BroadcastReceiver:是對(duì)發(fā)送出來的 Broadcast進(jìn)行過濾接受并響應(yīng)的一類組件,其本質(zhì)是一個(gè)監(jiān)聽器,用來監(jiān)聽系統(tǒng)全局的廣播信息

2.廣播機(jī)制工作原理:

如何發(fā)送Broadcast和使用BroadcastReceiver過濾接收:

2.1 首先在需要發(fā)送信息的地方,把要發(fā)送的信息和用于過濾的信息(如Action、Category)裝入一個(gè)Intent對(duì)象

2.2 然后通過調(diào)用 Context.sendBroadcast()、sendOrderBroadcast()或sendStickyBroadcast()方法,把Intent對(duì)象以廣播方式發(fā)送出去。

2.3 當(dāng)Intent發(fā)送以后,所有已經(jīng)注冊(cè)的BroadcastReceiver會(huì)檢查注冊(cè)時(shí)的IntentFilter是否與發(fā)送的Intent相匹配,若匹配則就會(huì)調(diào)用BroadcastReceiver的onReceive()方法

3.注冊(cè)BroadcastReceiver有兩種方式:

3.1 靜態(tài)的在AndroidManifest.xml中用<receiver>標(biāo)簽聲明注冊(cè),并在標(biāo)簽內(nèi)用<intent-filter>標(biāo)簽設(shè)置過濾器

3.2 動(dòng)態(tài)的在代碼中先定義并設(shè)置好一個(gè) IntentFilter對(duì)象,然后在需要注冊(cè)的地方調(diào) Context.registerReceiver()方法,如果取消時(shí)就調(diào)用Context.unregisterReceiver()方法。如果用動(dòng) 態(tài)方式注冊(cè)的BroadcastReceiver的Context對(duì)象被銷毀時(shí), BroadcastReceiver,也就自動(dòng)取消注冊(cè)了,動(dòng)態(tài)注冊(cè)退出程序前要記得調(diào)用Context.unregisterReceiver()方法

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(String);//BroadcastReceiver指定action,
image.gif

registerReceiver(BroadcastReceiver,intentFilter); (一般:在onStart中注冊(cè),onStop中取消unregisterReceiver;官方提醒,如果在Activity.onResume()里面注冊(cè)了,就必須在Activity.onPause()注銷)

4.兩種注冊(cè)方式的區(qū)別:

4.1 靜態(tài)注冊(cè)可以在xml里面一目了然,而動(dòng)態(tài)注冊(cè)方式,隱藏在代碼中,比較難發(fā)現(xiàn)

4.2 同一優(yōu)先級(jí)的廣播接收器,動(dòng)態(tài)的要比靜態(tài)注冊(cè)接受的早

sendBroadcast 發(fā)送的是無序廣播

sendOrderedBroadcast 發(fā)送的是有序廣播

5.指定接收的權(quán)限:

若在使用sendBroadcast()的方法是指定了接收權(quán)限,則只有在AndroidManifest.xml中用<uses-permission>標(biāo)簽聲明了擁有此權(quán)限的BroascastReceiver才會(huì)有可能接收到發(fā)送來的Broadcast

6.實(shí)現(xiàn)一個(gè)廣播接收器的步驟:

6.1第一步:繼承BroadcastReceiver,并重寫onReceive()方法。

public class IncomingSMSReceiver extends BroadcastReceiver{  
   @Override public void onReceive(Context context, Intent intent){ }  
}  
image.gif

6.2 第二步:訂閱感興趣的廣播Intent,訂閱方法有兩種:

第一種:使用代碼進(jìn)行訂閱

IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");  
IncomingSMSReceiver receiver = new IncomingSMSReceiver();  
registerReceiver(receiver, filter);  
image.gif

第二種:在AndroidManifest.xml文件中的<application>節(jié)點(diǎn)里進(jìn)行訂閱:

<receiver android:name=".IncomingSMSReceiver">  
     <intent-filter>  
          <action android:name="android.provider.Telephony.SMS_RECEIVED"/>  
     </intent-filter>  
</receiver>  
image.gif

7.常見廣播Intent:

一個(gè)receiver可以接收多個(gè)action的,即可以有多個(gè)intent-filter,需要在onReceive里面對(duì)intent.getAction(action name)進(jìn)行判斷

接受短信

action:android.provider.Telephony.SMS_RECEIVED

 permission:android.permission.RECEIVE_SMS

接收電池電量變化

action:android.intent.action.BATTERY_CHANGED

接收開機(jī)啟動(dòng)

aciton:android.intent.action.BOOT_COMPLETED

permission:andro.permission.RECEIVE_BOOT_COMPLETED

8.廣播接收器的生命周期:

在Android中,程序的響應(yīng)(Responsive)被活動(dòng)管理器(Activity Manager)和窗口管理器(Window Manager)這兩個(gè)系統(tǒng)服務(wù)所監(jiān)視。當(dāng)BroadcastReceiver的Receiver方法在10秒內(nèi)沒有執(zhí)行完畢,Android會(huì)認(rèn)為該程序無響應(yīng)。所以在BroadcastReceiver里不能做一些比較 耗時(shí)的操作,否則會(huì)彈出ANR(Application No Response)的對(duì)話框。

如果需要完成一項(xiàng)比較耗時(shí)的工作,應(yīng)該通過Intent啟動(dòng)一個(gè)Service來完成,而不是啟動(dòng)一個(gè)新的線程來完成,因?yàn)锽oradcastReveiver的生命周期非常短暫,有可能在子線程還沒有執(zhí)行完畢,BroadcastReceiver就提前退出了,這樣在進(jìn)程中沒有任何的活動(dòng)組件,系統(tǒng)在內(nèi)存緊張的情況下優(yōu)先結(jié)束該進(jìn)程,導(dǎo)致BroadcastReceiver啟動(dòng)的子線程不能執(zhí)行完成

一個(gè)BroadcastReceiver,每接受一次就是產(chǎn)生一個(gè)新的接收器對(duì)象 對(duì)象只有在被調(diào)用onReceive(Context, Intent)的才有效的,當(dāng)從該函數(shù)返回后,該對(duì)象就無效的了,結(jié)束生命周期     
public class IncomingSMSReceiver extends BroadcastReceiver {   
    //發(fā)送Intent啟動(dòng)服務(wù),由服務(wù)來完成比較耗時(shí)的操作  
    Intent service = new Intent(context, XxxService.class);  
    context.startService(service);  
}   
image.gif

9.廣播接收器分類:

Normal Broadcast(普通廣播):

1.1 完全是異步的的,理論上可以在同一時(shí)刻被所有接收器所接受,傳播效率高

1.2 廣播接收器無法將處理結(jié)果傳遞給下一個(gè)接收者

1.3 廣播接收器無法阻止廣播信息的傳播

Ordered Broadcast(有序廣播):

1.1 可以按照廣播接收器預(yù)先設(shè)置的優(yōu)先級(jí)依次接受Broadcast(優(yōu)先級(jí)聲明在<IntentFilter...>的android:priority屬性中,數(shù)越大優(yōu)先級(jí)越高,取值范圍在-1000~1000之間)

1.2 廣播接收器可以終止廣播的傳播(abortBroadcast()),一旦終止,后面的廣播接收器將無法接收到廣播消息,也無法接收廣播接收器所傳遞的信息

1.3 廣播接收器可以將處理結(jié)果傳遞給下一個(gè)接收者(前提條件,廣播沒有終止)

小結(jié):沒有終止廣播信息和結(jié)果數(shù)據(jù)能接收,若終止廣播信息和結(jié)果數(shù)據(jù)都不能接收

setResultExtras(bundle);//將廣播消息的處理結(jié)果存入結(jié)果對(duì)象

abortBroadcast();//終止發(fā)送廣播

Bundle bundle = getResultExtras(true);//接收所傳遞的廣播結(jié)果對(duì)象

String first = bundle.getString("first");

10.UI事件監(jiān)聽器機(jī)制和廣播事件處理機(jī)制的聯(lián)系與區(qū)別:

聯(lián)系:都是基于事件監(jiān)聽處理機(jī)制

9.1 UI事件處理機(jī)制是程序組件級(jí)別的(比如:按鈕的單擊事件),而廣播事件處理機(jī)制是系統(tǒng)級(jí)別的

9.2 UI事件監(jiān)聽器的注冊(cè)只能在代碼中實(shí)現(xiàn),而廣播放事件的監(jiān)聽器可以在代碼中注冊(cè)也可以在xml配置文件里面注冊(cè)

9.3 UI事件監(jiān)聽器的處理和主程序是同步的,而是廣播放事件的事件處理是異步的

9.4 UI事件監(jiān)聽器監(jiān)聽的是程序中的對(duì)象,而廣播放事件的監(jiān)聽器監(jiān)聽的事件源是Android應(yīng)用中其他的組件

**5.1.4 ******ListView布局 ****

ListView 如果僅僅出于功能上的需求ListView可能沒有存在的必要,ListView能作的事情基本上ScrollView也能勝任。ListView存在的最根本的原因在于它的高效(如何實(shí)現(xiàn)的?).ListView通過對(duì)象的復(fù)用從而減少內(nèi)存的消耗,也減少了對(duì)象的創(chuàng)建從而也減少的cpu的消耗(在Androidk中創(chuàng)建View對(duì)象經(jīng)常伴隨著解析xml)。ListView的本質(zhì)是一張bitmap(當(dāng)然所有的控件文字等在屏幕上看到的最終都會(huì)變成bitmap),ListView會(huì)按照需求,根據(jù)Adapter提供的信息把需要的Item畫出來顯示在屏幕上,當(dāng)屏幕滾動(dòng)的時(shí)候會(huì)重新計(jì)算Item的位置并繪制出新的bitmap顯示在屏幕上。這樣聽起來感覺可能不是很高效,但這樣帶的好處就是,每用為一第個(gè)Item 創(chuàng)建一個(gè)View對(duì)象,樣式一樣的對(duì)象可以共用一個(gè)View對(duì)象,減少了內(nèi)存的消耗。而且ListView是事件驅(qū)動(dòng)的,只有當(dāng)需要的時(shí)候才會(huì)重新繪制,并且只會(huì) 繪制當(dāng)前屏幕上所顯示的Items.

ListView 離不開Adapter,通常的作法創(chuàng)建一個(gè)類繼承BaseAdapter,Override getCount()和getView()等方法。生成這個(gè)類的對(duì)象,調(diào)用ListView的setAdapter()與ListViw進(jìn)行綁定。

ListView會(huì)調(diào)用跟其綁定的Adapter的getCount()方法知道有多少個(gè)Item需要展示,然后循環(huán)調(diào)用getView(int position, View convertView, ViewGroup parent)知道第position個(gè)Item該怎么畫,并畫出來直到把當(dāng)前的ListView的空間填滿。當(dāng)Adapter當(dāng)中的數(shù)據(jù)改變時(shí),需調(diào)用notifyDataSetChanged ()告訴Adapter數(shù)據(jù)發(fā)生了變化或者給Adapter注冊(cè)一個(gè)觀察者registerDataSetObserver (DataSetObserver observer)。當(dāng)Adapter得知與其綁定的數(shù)據(jù)己發(fā)生改變時(shí)間,會(huì)再次調(diào)用getCount()方法,并循環(huán)調(diào)用getView(int position, View convertView, ViewGroup parent)刷新當(dāng)前頁面

[圖片上傳失敗...(image-80d611-1555414018806)]

image.gif

?
image
image.gif

?

**5.1.5 ******GridView布局****

a.需要?jiǎng)?chuàng)建GridView xml布局文件

必須定義的屬性(列數(shù),列寬,對(duì)其方式),android:numColumns="auto_fit" android:columnWidth="90" android:gravity="center"

b.創(chuàng)建數(shù)據(jù)適配器ImageAdapter(注意一定要給imageViewz賦值)

if(convertView==null){
    //設(shè)置ImageView的資源
    ImageView imageView = new ImageView(mContent);
    //設(shè)置圖片的尺寸
    imageView.setLayoutParams(new GridView.LayoutParams(85,85));
    //設(shè)置顯示比例類型
    imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
}else{
    imageView = (ImageView)convertView;
}

imageView.setImageResource(imgArr[position]);
image.gif

c.設(shè)置Activity的布局文件,并獲得GriwView,并且設(shè)置它的適配器

setContentView(R.layout.gridview);

d.獲取GridView控件

GridView gv = (GridView)findViewById(R.id.gridView);

e.設(shè)置GridView的匹配器

gv.setAdapter(new ImageAdapter(this));

f.設(shè)置網(wǎng)格元素的監(jiān)聽器

gv.setOnItemClickListener(new AdapterView.onItemClickListener(){});

**5.1.6 ******翻頁技術(shù)****

[圖片上傳失敗...(image-46648f-1555414018806)]

image.gif

?
image
image.gif

?

實(shí)現(xiàn)原理:

使用貝賽爾曲線。曲線有四個(gè)點(diǎn):起始點(diǎn)、終止點(diǎn)(也稱錨點(diǎn))以及兩個(gè)相互分離的中間點(diǎn)。滑動(dòng)兩個(gè)中間點(diǎn),貝塞爾曲線的形狀會(huì)發(fā)生變化。

根據(jù)第一種翻頁效果原理可以確定a、e、h、f、g ,由eh平行于cj且af垂直于eh,則 af垂直于cj則三角形egf相似于三角形cnf 則有ef:cf = gf:nf 。

設(shè)n為ag中點(diǎn) 則有cf=(3/2)*ef ,則c點(diǎn)坐標(biāo)可求 由c點(diǎn)、k點(diǎn)坐標(biāo)已知可知過兩點(diǎn)間的直線

由該直線可計(jì)算與y軸相交點(diǎn)j 由a、e、c、j可計(jì)算兩條直線的相交點(diǎn)b 同理可求點(diǎn)k。

在Android中的具體實(shí)現(xiàn)步驟:

起始頁展示

1.創(chuàng)建屏幕尺寸的bmp 2.將圖片轉(zhuǎn)化為canvas 3.獲取起始頁面數(shù)據(jù) 3.在canvas中繪制起始頁數(shù)據(jù) 4.在當(dāng)前視圖中復(fù)寫onDraw進(jìn)行重繪出bmp對(duì)象

翻頁處理

1.初始化時(shí)創(chuàng)建兩個(gè)bmp(bmp1、bmp2)并將其轉(zhuǎn)換為canvas(canvas1、canvas2)

2.獲取手勢首次觸摸的區(qū)域 (例:當(dāng)首次點(diǎn)擊屏幕的位置x<50&&y<50則為左上角)

3.根據(jù)首次點(diǎn)擊區(qū)域判斷需要展示的數(shù)據(jù)(例:首次點(diǎn)擊處于左側(cè)區(qū)域【左上、左下】的則判斷操作為下一頁操作)

4.獲取下一頁中數(shù)據(jù)并繪制出來在canvas2中

5.根據(jù)1中獲取的區(qū)域位置調(diào)用起始動(dòng)畫使視圖移動(dòng)到手勢首次點(diǎn)擊位置

6.獲取手勢每次移動(dòng)的坐標(biāo)并根據(jù)移動(dòng)坐標(biāo)計(jì)算繪制的各個(gè)點(diǎn)的坐標(biāo)

7.每次移動(dòng)刷新視圖

**5.2 ******相關(guān)界面****

**5.2.1 ******首頁****

[圖片上傳失敗...(image-767cbb-1555414018806)]

image.gif

?
image
image.gif

?

**5.2.2 ******報(bào)紙閱讀頁****

[圖片上傳失敗...(image-ceec97-1555414018805)]

image.gif

?
image
image.gif

?

**5.2.3 ******報(bào)紙列表頁****

[圖片上傳失敗...(image-8ac5ec-1555414018805)]

image.gif

?
image
image.gif

?

**5.3 ******相關(guān)實(shí)現(xiàn)****

**5.3.1 ******首頁****

Android的每一個(gè)可視化界面,都有其唯一的布局配置文件,該文件中有各種布局的方式,和各種資源文件如圖像,文字,顏色引用等,程序在運(yùn)行時(shí)可以通過代碼對(duì)各個(gè)配置文件進(jìn)行讀取,這樣可以形成不同的可視化界面和絢麗的效果。

該軟件的主界面是一個(gè)Activity,Android工程在啟動(dòng)每一個(gè)Activity時(shí)都會(huì)首先執(zhí)行onCreate()方法,如下:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}
image.gif

該方法主要執(zhí)行界面的初始化操作,Activity有個(gè)設(shè)置布局的方法:

setContentView(int id)
image.gif

最新報(bào)紙代碼實(shí)現(xiàn):

paper = (Paper) bundle.getSerializable("paper");
Bitmap bitmapZxbz = bundle.getParcelable("bitmapZxbz"); publishDateTv.setText(paper.getPublishDate().toString());
paperSizeTv.setText(paper.getSize()+"");
paperImgIv.setImageBitmap(bitmapZxbz);
image.gif

本期導(dǎo)讀代碼實(shí)現(xiàn):

listArticle = (List<Article>) bundle.getSerializable("listArticle");
List<HashMap<String,String>> listArticleMap = new ArrayList<HashMap<String,String>>();

LayoutParams params = bqddLv.getLayoutParams();    
params.height = listArticle.size()*42;           
bqddLv.setLayoutParams(params); 

 BqddArrayAdapter adapterBqdd = new BqddArrayAdapter(IndexActivity.this,R.layout.bqdd,listArticle);
 bqddLv.setAdapter(adapterBqdd);
 bqddLv.setOnItemClickListener(new BqddLvOnItemClickListener());
 bqddLv.setItemsCanFocus(true);   
image.gif

過往瀏覽代碼實(shí)現(xiàn):

String[] picGwllArr = bundle.getStringArray("picGwllArr");
gwllGridView.setAdapter(new GwllImageAdapter(IndexActivity.this,picGwllArr));
image.gif

翻頁代碼實(shí)現(xiàn):

BookLayout bk = new BookLayout(PaperReadActivity.this,listPage);
BookAdapter ba = new BookAdapter(PaperReadActivity.this,pageArr,false);   
bk.setPageAdapter(ba);
setContentView(bk);
image.gif

**5.3.2 ******報(bào)紙閱讀頁****

BookLayout bk = new BookLayout(PaperReadActivity.this,listPage);
BookAdapter ba = new BookAdapter(PaperReadActivity.this,pageArr,false);
bk.setPageAdapter(ba);
setContentView(bk);
image.gif

**5.3.3 ******報(bào)紙列表頁****

private void InitLayout() {
//得到ScrollView控件
waterfall_scroll = (LazyScrollView) findViewById(R.id.waterfall_scroll);
//的到ScrollView控件下的子控件
waterfall_scroll.getView();
//給ScrollView綁定滑屏監(jiān)聽器
waterfall_scroll.setOnScrollListener(new OnScrollListener() {
@Override
public void onTop() {
// 滾動(dòng)到最頂端
Log.d("LazyScroll", "Scroll to top");
}

@Override
public void onScroll() {
// 滾動(dòng)中
Log.d("LazyScroll", "Scroll");
}

@Override
public void onBottom() {
// 滾動(dòng)到最低端 調(diào)用該方法
AddItemToContainer(++current_page, page_count);
}
});

//得到線性布局控件
waterfall_container = (LinearLayout) this.findViewById(R.id.waterfall_container);
//實(shí)例化線性布局控件集合
waterfall_items = new ArrayList<LinearLayout>();
//循環(huán)給線性控件集合賦值,并將子控件添加到父控件
for (int i = 0; i < column_count; i++) {
System.out.println("--------->"+i);
LinearLayout itemLayout = new LinearLayout(this);
LinearLayout.LayoutParams itemParam = new LinearLayout.LayoutParams(itemWidth, LayoutParams.WRAP_CONTENT);
// itemParam.width = itemWidth;
// itemParam.height = LayoutParams.WRAP_CONTENT;
itemLayout.setPadding(2, 2, 2, 2);
itemLayout.setOrientation(LinearLayout.VERTICAL);
itemLayout.setLayoutParams(itemParam);
waterfall_items.add(itemLayout);
waterfall_container.addView(itemLayout);
}

image.gif

**6 ******結(jié)論****

通過對(duì)Android智能手機(jī)報(bào)系統(tǒng)的開發(fā),對(duì)Android下Http網(wǎng)絡(luò)通信機(jī)制有了深入的了解,熟悉了Android開發(fā)架構(gòu)和API調(diào)用, 掌握了多線程開發(fā)技術(shù),熟練Android平臺(tái)UI布局,熟練常用控件使用,通過項(xiàng)目實(shí)踐認(rèn)識(shí)到整個(gè)開發(fā)過程中就是圍繞著一個(gè)數(shù)據(jù),Activity顯示數(shù)據(jù),Service處理數(shù)據(jù),Intent傳遞數(shù)據(jù),BroadcastReceiver接收數(shù)據(jù),ContentProvider共享數(shù)據(jù),對(duì)Adroid平臺(tái)提供的幾大基本組件有深刻的理解和認(rèn)識(shí)

Activity:是整個(gè)應(yīng)用程序的門面,主要負(fù)責(zé)應(yīng)用程序當(dāng)中數(shù)據(jù)的展示,是各種各樣控件的容器,是用戶和應(yīng)用程序之間交互的接口 (美女)

Service:在前臺(tái)不可見,但是承擔(dān)大部分?jǐn)?shù)據(jù)處理工作,Service和Activity的地位是并列的,他也代表一個(gè)單獨(dú)的Android組件,區(qū)別在于:Activity運(yùn)行與前臺(tái),Service通常位于后臺(tái)運(yùn)行,他一般需要與用戶交互,因此Service沒有圖形用戶界面,通常他為其他的組件提供后臺(tái)服務(wù)或監(jiān)控其他組件的運(yùn)行狀態(tài)(勞模)

Intent:是應(yīng)用程序種各個(gè)組件聯(lián)系的橋梁,主要負(fù)責(zé)應(yīng)用程序中所有數(shù)據(jù)的傳遞(運(yùn)輸大隊(duì)長)

BroadcastReceiver:他主要是實(shí)現(xiàn)了不同的應(yīng)用程序之間數(shù)據(jù)的異步接收,其本質(zhì)是一個(gè)事件監(jiān)聽器,用于監(jiān)聽系統(tǒng)全局的廣播消息(廣播接收器)

ContentProvider:負(fù)責(zé)不同應(yīng)用程序之間數(shù)據(jù)的共享,為不同的應(yīng)用程序之間數(shù)據(jù)訪問提供統(tǒng)一的接口 ,這個(gè)接口就是ContentHandler,具體就是要實(shí)現(xiàn)如下的四個(gè)抽象方法insert(),delete(),update(),query(),通常它與ContentResolver結(jié)合使用,一個(gè)是應(yīng)用程序使用ContentProvider來暴露自己的數(shù)據(jù),而另外一個(gè)是應(yīng)用程序通過ContentResolver來訪問數(shù)據(jù)(國家檔案館)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容