導航:首頁 > 操作系統 > android項目開發範例

android項目開發範例

發布時間:2023-06-19 20:52:41

A. android-Ble藍牙開發Demo示例–掃描,連接,發送和接收數據,分包解包(附源碼)

萬物互聯的物聯網時代的已經來臨,ble藍牙開發在其中扮演著舉重若輕的角色。最近剛好閑一點,抽時間梳理下這塊的知識點。

涉及ble藍牙通訊的客戶端(開啟、掃描、連接、發送和接收數據、分包解包)和服務端(初始化廣播數據、開始廣播、配置Services、Server回調操作)整個環節以及一些常見的問題即踩過的一些坑。

比如
1、在Android不同版本或不同手機的適配問題,掃描不到藍牙設備
2、如何避免ble藍牙連接出現133錯誤?
3、單次寫的數據大小有20位元組限制,如何發送長數據

藍牙有傳統(經典)藍牙和低功耗藍牙BLE(Bluetooth Low Energy)之分,兩者的開發的API不一樣,本文主講Ble藍牙開發,傳統藍牙不展開,有需要的可以自行了解。

相對傳統藍牙,BLE低功耗藍牙,主要特點是快速搜索,快速連接,超低功耗保持連接和數據傳輸。

客戶端

服務端

Android4.3(API Level 18)開始引入BLE的核心功能並提供了相應的 API。應用程序通過這些 API 掃描藍牙設備、查詢 services、讀寫設備的 characteristics(屬性特徵)等操作。

BLE藍牙協議是GATT協議, BLE相關類不多, 全都位於android.bluetooth包和android.bluetooth.le包的幾個類:
android.bluetooth.
.BluetoothGattService 包含多個Characteristic(屬性特徵值), 含有唯一的UUID作為標識
.BluetoothGattCharacteristic 包含單個值和多個Descriptor, 含有唯一的UUID作為標識
.BluetoothGattDescriptor 對Characteristic進行描述, 含有唯一的UUID作為標識

.BluetoothGatt 客戶端相關
.BluetoothGattCallback 客戶端連接回調
.BluetoothGattServer 服務端相關
.BluetoothGattServerCallback 服務端連接回調

android.bluetooth.le.
.AdvertiseCallback 服務端的廣播回調
.AdvertiseData 服務端的廣播數據
.AdvertiseSettings 服務端的廣播設置
.BluetoothLeAdvertiser 服務端的廣播

.BluetoothLeScanner 客戶端掃描相關(Android5.0新增)
.ScanCallback 客戶端掃描回調
.ScanFilter 客戶端掃描過濾
.ScanRecord 客戶端掃描結果的廣播數據
.ScanResult 客戶端掃描結果
.ScanSettings 客戶端掃描設置

BLE設備分為兩種設備: 客戶端(也叫主機/中心設備/Central), 服務端(也叫從機/外圍設備/peripheral)
客戶端的核心類是 BluetoothGatt
服務端的核心類是 BluetoothGattServer 和 BluetoothLeAdvertiser
BLE數據的核心類是 BluetoothGattCharacteristic 和 BluetoothGattDescriptor

下面詳細講解下客戶端和服務端的開發步驟流程

安卓手機涉及藍牙許可權問題,藍牙開發需要在AndroidManifest.xml文件中添加許可權聲明:

在搜索設備之前需要詢問打開手機藍牙:

注意: BLE設備地址是動態變化(每隔一段時間都會變化),而經典藍牙設備是出廠就固定不變了!

通過掃描BLE設備,根據設備名稱區分出目標設備targetDevice,下一步實現與目標設備的連接,在連接設備之前要停止搜索藍牙;停止搜索一般需要一定的時間來完成,最好調用停止搜索函數之後加以100ms的延時,保證系統能夠完全停止搜索藍牙設備。停止搜索之後啟動連接過程;

BLE藍牙的連接方法相對簡單只需調用connectGatt方法;

參數說明

與設備建立連接之後與設備通信,整個通信過程都是在BluetoothGattCallback的非同步回調函數中完成;

BluetoothGattCallback中主要回調函數如下:

上述幾個回調函數是BLE開發中不可缺少的;

當調用targetdDevice.connectGatt(context, false, gattCallback)後系統會主動發起與BLE藍牙設備的連接,若成功連接到設備將回調onConnectionStateChange方法,其處理過程如下:

判斷newState == BluetoothGatt.STATE_CONNECTED表明此時已經成功連接到設備;

mBluetoothGatt.discoverServices();

掃描BLE設備服務是安卓系統中關於BLE藍牙開發的重要一步,一般在設備連接成功後調用,掃描到設備服務後回調onServicesDiscovered()函數,函數原型如下:

BLE藍牙開發主要有負責通信的BluetoothGattService完成的。當且稱為通信服務。通信服務通過硬體工程師提供的UUID獲取。獲取方式如下:

具體操作方式如下:

開啟監聽,即建立與設備的通信的首發數據通道,BLE開發中只有當客戶端成功開啟監聽後才能與服務端收發數據。開啟監聽的方式如下:

BLE單次寫的數據量大小是有限制的, 通常是20位元組 ,可以嘗試通過requestMTU增大,但不保證能成功。分包寫是一種解決方案,需要定義分包協議,假設每個包大小20位元組,分兩種包,數據包和非數據包。對於數據包,頭兩個位元組表示包的序號,剩下的都填充數據。對於非數據包,主要是發送一些控制信息。
監聽成功後通過向 writeCharacteristic寫入數據實現與服務端的通信。寫入方式如下:

其中:value一般為Hex格式指令,其內容由設備通信的藍牙通信協議規定;

若寫入指令成功則回調BluetoothGattCallback中的onCharacteristicWrite()方法,說明將數據已經發送給下位機;

若發送的數據符合通信協議,則服務端會向客戶端回復相應的數據。發送的數據通過回調onCharacteristicChanged()方法獲取,其處理方式如下:

通過向服務端發送指令獲取服務端的回復數據,即可完成與設備的通信過程;

當與設備完成通信之後之後一定要斷開與設備的連接。調用以下方法斷開與設備的連接:

源碼上傳在CSDN上了,有需要的可以借鑒。

=====> Android藍牙Ble通訊Demo示例源碼–掃描,連接,發送和接收數據,分包解包

BLE單次寫的數據量大小是有限制的,通常是20位元組,可以嘗試通過requestMTU增大,但不保證能成功。分包寫是一種解決方案,需要定義分包協議,假設每個包大小20位元組,分兩種包,數據包和非數據包。對於數據包,頭兩個位元組表示包的序號,剩下的都填充數據。對於非數據包,主要是發送一些控制信息。
總體流程如下:
1、定義通訊協議,如下(這里只是個舉例,可以根據項目需求擴展)

2、封裝通用發送數據介面(拆包)
該介面根據會發送數據內容按最大位元組數拆分(一般20位元組)放入隊列,拆分完後,依次從隊列里取出發送

3、封裝通用接收數據介面(組包)
該介面根據從接收的數據按協議里的定義解析數據長度判讀是否完整包,不是的話把每條消息累加起來

4、解析完整的數據包,進行業務邏輯處理

5、協議還可以引入加密解密,需要注意的選演算法參數的時候,加密後的長度最好跟原數據長度一致,這樣不會影響拆包組包

一般都是Android版本適配以及不同ROM機型(小米/紅米、華為/榮耀等)(EMUI、MIUI、ColorOS等)的許可權問題

藍牙開發中有很多問題,要靜下心分析問題,肯定可以解決的,一起加油;

B. 如何搭建android開發環境_如何搭建一個Android開發環境

我的第一個Android程序

今天給大家分享一下我的第一個Android項目:helloword

首先我們開發Android程序需要一個開發環境,下面先分享一下環境搭建的方法

Android開發環境搭建非常簡單,google為我們提供了一套洞吵完整的開發工具包下載

點擊DownloadtheSDK就會出現下面的頁面,選擇同意以上條款,並根據自己的系統選擇對應的版本,我的電腦是32位的所以就選擇了32-bit的,然後點擊下面藍色的按鈕就可以開始下載啦~~

下載好了之後呢是一個510M的壓縮文件,選擇好目錄解桐茄壓縮之後能我們會得到

這三個東西,這里呢我們看到了我們熟悉的Eclipse文件夾了,沒錯,這個文件夾下呢就是我們的開發工具啦,但是不要著急,但開始之前呢,局顫察我們需要先配置一下我們的環境變數

將SDK下的platform-tools和tools兩個文件夾的完整路徑呢配置到我們的環境變數PATH中

我的系統是window7的,配置環境變數的方法呢:右擊我的電腦->屬性->高級設置->環境變數->雙擊Path將連個文件夾的路徑追加進去,注意中間要用分號隔開,點擊確定。

配置好所有的環境變數後,打開我們的Eclipse文件夾下的eclipse.exe,第一次打開會彈出一個對話框,設置我們的工作路徑,也就是我們保存項目的地方

經過載入之後呢,我們就看到操作界面了。

首先先創建一個Android的虛擬機,點擊window下的AndroidVirtualDevicesManager選項

就可以看到我們的Android虛擬機管理界面了

點擊new新建一個虛擬機

選擇好後點擊確定,一個虛擬機就創建好了,選擇我們創建好,選中我創建好的虛擬機,start

載入界面

完成後就能看到我們的虛擬機啦~經過漫長的啟動終於看到虛擬機界面了。

准備工作都做好了,下面開始創建一個Android項目啦,萬能的helloword,哈哈!

虛擬機最小化,進入Eclipse界面,菜單欄File->new->Androidapplicationproject,新建一個Android項目

接著會出現一個界面,選擇一些參數

接下來就是一路next然後finish,一個新的Android項目就建好了

接著在界面會看到Eclipse的界面了

右擊我們的項目,runas->選擇Androidapplication,就可以運行到我們的虛擬機上

C. 如何創建一個Android開發項目

工具/材料

電腦

android studio

D. 《GoogleAndroidSDK開發範例大全》pdf下載在線閱讀,求百度網盤雲資源

《Google Android SDK開發範例大全》(余志龍//陳昱勛//鄭名傑//陳小鳳//郭秩均|改編)電子書網盤下載免費在線閱讀

鏈接:https://pan..com/s/1UhHOPp6lo7VDFOmYrOINNg

密碼:xsg8

書名:早悉畢Google Android SDK開發範例大全

作者:余志龍//陳昱勛//鄭名傑//陳小鳳//郭秩均|改編

豆瓣評分:7.3

出版社:人民郵電

出版年份:2010-6

頁數:654

內容簡介:

《Google Android SDK開發範例大全(第2版)》在上一版陸芹的基礎上,以Android手機應用程序開發(採用AndroidSDK2.1)為主題,通過160多個範例全面且深度地整合了手機、網陸租絡及服務等多個開發領域,為讀者提高程序設計功力提供了很大的幫助。

全書共分10章,主要以範例集的方式來講述Android的知識點,詳細介紹了開發Android的人機交互界面、Android常用的開發控制項、使用Android手機收發簡訊等通信服務、開發Android手機的自動服務功能和娛樂多媒體功能以及整合Android與Aoogle強大的網路服務等內容。隨書光碟中包括了所有範例的程序代碼。

《Google Android SDK開發範例大全(第2版)》講述由淺入深,由Android的基礎知識到實際開發應用,結構清晰、語言簡潔,非常適合Android的初學者和Android的進階程序開發者閱讀參考。

更強大的手機服務×更先進的影音功能×更優化的G00gIe服務整合,更多不容錯過的精彩範例。

《Google Android SDK開發範例大全(第2版)》範例繼承Java優良傳統,使用開放架構。彈性修改隨心所欲。

易於閱讀的架構設計,每個範例均搭配步驟及完成畫面!

汲取專家開發經驗,指引快速上手捷徑。

E. Android開發之Java設計模式基礎篇


今天我們就Android開發中的一些設計模式做一些基礎性的掌握,本次就Android項目的架構設計相關內容做分析:
1. 靜態工廠方法
靜態工廠方法可以算是工廠方法加單例模式的整合在Android平台上,由於Android的Context可以很好的傳遞實例,靜態工廠方法可以提到傳統的類構造器,對於一些邏輯的服務提供類可以考慮這樣的設計,比如文件下載、圖片裁剪等操作。
2. Java的類訪問許可權
對於程序的可靠性而言,成員變數盡量私有,通過暴漏公開的方法來訪問這些私有成員,提供類似getXXX和setXXX這樣的散枝方法,不僅是Java,這點C#對於屬性的操作概念在Dot Net上已經深入人心,好處就是可以阻止繼承後的訪問換亂問題。
3. 使用枚舉替代常量
Java在明橡JDK 1.5開始加入了enum枚舉類,相對於常規的final int這樣的定義一些常量更簡單安全,畢竟常量是一堆類似整形的數值,列印起來沒有過多的意義,枚舉對於繼承後訪問的清晰度可以很好的杜絕隱患發生。
4. 使用列表優先於數組
Java的集合類很方便,使用List類的列表在開銷上比Object [ ] 這樣的數組大,但是對於泛型的支持而言更好用強大。也可以避免一些不必要的錯誤,比如
cwjObject [] obj= new int[1];
obj[1] = "android開發網測試"; //這樣會在運行時拋出類似ArrayStoreException這樣的異常。
而使用列表則為:
ListcwjObject obj=new ArrayListint();
obj.add("android123測試"); // 由於傳入列表的是字元串,和構造時類型的int不同,在編譯時就提示錯誤,可以避免一些不必要的情況發生。
5. Java的foreach代替for
Java的foreach仍然使用for來寫,這點和C#直接用foreach關鍵字有點不同,但是使用方法是一樣的,除了更簡潔外,其實foreach比傳統的for更加優激掘旁化,比如傳統的for第二個限制位,一般訪問屬性或方法,比如說
for (int x=0;xobj.size();x++) //這句的限制符號每次都會執行obj.size() 方法,當然Android開發網相信size()方法訪問的是一個數組的length屬性,活著是
for (int y=0;yobj.length;y++) //這里同樣每次循環都執行obj.length對於Java VM的開銷主要由這個obj的長度決定的,而Android SDK文檔的推薦方式是
int nSize=obj.size() 或 int nSize=obj.length
for (int z=0;znSize;z++) ,但是這還不是最優的方法,下面Android123給大家更好的foreach方式的替代方法:
for (SmartObject singleObj : SmartObjectArray)
{
singleObj.setName("cwj"); 或 singleObject.strName="cwj";
}
有關Android開發中的Java設計模式技巧,希望國內Android開發者打好Java基礎,別扎堆實現鋪天蓋地的應用,目前不說惡意軟體問題,就大部分的軟體設計質量令人擔憂,還有很多應用基本上就是J2EE或J2SE開源項目的移植版。

F. 如何編寫安卓軟體

問題一:如何用eclipse編寫安卓程序 方法/步驟
1
1)首先,下載android SDK.介紹一種非常簡單的方法,一並下載eclipse.在網路中輸入android SDK,進入搜索界面。選中第一條。
2)如果你已經有eclipse,你可以直接在eclipse中進行android SDK插件的安裝。方法就是點擊上面菜單里的help,選擇install new software進行添加SDK。具體方法見經驗如何在eclipse中添加android SDk。
2
進入下載界面後,選擇適合自己電腦的SDK進行下載。這里下載的是android開發工具,非常的簡單實用,不需要我么重新下載eclipse,在這個下載包中會自帶一個eclipse FOR android的develop工具,我們直接在裡面就可以進行android的開發。
3
下載完成後解壓,解壓後我們進入文件名為eclipse的文件夾中。點擊eclipse應用程序,運行。運行如圖,和我們常用的eclipse是不一樣的因為這個是android的開發工具,只適用於開發android。裡面有好的插件已經提供給我們,不需要再進行安裝。
4
進入eclipse界面後,開始新建android項目。輸入新建項目名,如果沒有特殊要求,點擊next一直至最後完成。開始的配置只是一個大體的框架的構建,這些我們可以以後進行修改,最總要的還是代碼的編寫。
5
所有配置都完成後就可以開始進行android的開發了。如圖:
進行android開發的時候建議不要用拖拽控制項的方式,建議直接編寫代碼。
END
java環境變數配置
1
這里順便介紹一下java環境變數的配置。
1)首先打開環境變數的界面,添加一個JAVA_HOME的值。右擊計算機屬性,在左側有高級設置,進入後就會看見環境變數選項了。
2)在系統變數中建立java_home,將你的java SDK所在的路徑放在裡面。
2
建立classpath。同樣在系統變數中新建一個classpath,在下面輸入.;即可,不用輸入其他的值。
3
運行cmd,測試。按win+R打開命令面板,輸入cmd,進入後輸入java -version然後回車,接著輸入javac,回車,看結果是否與下圖相同。
這里需要注意的是java -version的java後面是有空格的。

問題二:如何開發安卓第一個程序Hello World 1
打開eclipse集成sdk開發環境,點擊菜單file――》new――》Android application新建安卓項目
2
輸入工程名,項目名,還有包名,點擊下一步。
3
信心勾選不要更改,點擊下一步。
4
這個步驟是選擇應用的啟動圖標,如果想改就改,不想改就點擊下一步
5
選中blackActivity,點擊下一步
6
輸入activity的名稱,main的名稱,點擊下一步。
7
項目創建好了,右鍵要啟動的項目,run as 選中Android application啟動項目
8
然後模擬器啟動好之後,點擊查看,helloworld就創建好了

問題三:如何自學 Android 編程 因為項目需要,8月中旬開始決定做安卓的程序,所以馬上就開始學習安卓方面的開發知識,把最近的學習實踐經歷和大家分享分享。不要一開始就下載一大堆資料,視頻,然後就不知道做什麼了,要給自己定個目標,我要做什麼?我怎麼達到目標?
我不懂java,但是懂C#和C++,所以我沒主張去單獨學習java語言,如果你是個最最初的新手,沒啥語言基礎,那你必須先看看java語言,不要很詳細看,因為學習Android中,你也是在學習java。
1. 明確目標
沒有目標的學習,會感覺到後面沒什麼成果,在1年前,我也打算學習android開發的,但是目的就是學習,到網上去下載很多學習的視頻,然後把開發環境搭建起來,能把Helloworld運行起來,能打些log,Activity之間也能互相切換了,但是後面也就不了了之了,因為不知道學了要干什麼。依葫蘆畫瓢的做了幾個例子,因為裡面的問題都是已經解決的,所以也沒能深入的系統學習。
這次因為產品的需要,要做Android版本,要做的東西一開始就已經設計好了,見搖搖2選1安卓版本,剛開始也不知道裡面有些什麼技術難度,但是要做的目標已經明確了,而且也沒有現成的,碰到問題就查資料,慢慢地解決,這樣有的放矢,學習的效果非常好。既有現成的技術可以使用,又有些技術,需要查比較多的資料,這樣記憶就比較深刻,所掌握的知識也比較系統。
接下來的一系列文章,我會把在開發搖搖2選1中遇到的問題,給大家詳細講講,程序雖然小,但是五臟俱全,做Demo和做產品的要求完全不是一個級別,如果Android大牛感覺知識講的比較淺,那可以繞道,畢竟我是從一個完全的新手開始的。
2. 了解安卓開發中比較困難的地方
學習一個新平台,就要知道此平台開發要面臨的困難有哪些,不要做到最後,這些問題沒有考慮,那就比較糟糕了。在網上搜索了下,安卓開發困難總結如何:
1)安卓系統版本比較多,各版本之間的兼容性是個問題,此為系統碎片。
2)安卓設備千變萬化,設備難以統一,每個產品都成為獨立,分散的Android碎片。
3)解析度五花八門。一個產品,可能需要多個界面排版,人工消耗比較大。
看到這張圖,有沒有頭疼的感覺?
總結成一句話:Android的碎片化真是要來開發者的命。
3. 搭建開發環境
巧婦難為無米之炊,開發環境肯定是第一件要做的事情,這類的文章已經很多了,我也不多說了,多說也就比較無聊了。感謝吳秦,也是博客園里的一員,他寫的很詳細了,見這里。
4. 查看網友總結的一些經驗。
不是什麼都查看,開發中遇到什麼問題,就去查看什麼問題,這樣你查到的知識,馬上就能深入的實踐,這樣知識就鞏固了。
1)首先當然要看Android的開發文檔,裡面其實大部分的知識都有了,還有就是SDK自帶的Samples。
2)博客園里搜索「Android開發」,會出來一大把,很多網友都是很系統的講解了。
3)eoe
android社區,裡面有很多網友上傳了現成的demo代碼,裡面很多都是模仿現在流行的產品的界面開發,很是不錯。
5. 掌握調試方法
個人一直認為,調試技巧是開發中最重要的技能,如果調試技能比較差,不知道如何查找問題,那不會是個好的程序員,其技能也不會高到哪裡去。
Android做下來,感覺調試這塊做的很不錯了,這要感謝Eclipse
IDE做的比較不錯,但是Android的界面排版部分,真的不敢恭維,Eclips......>>

問題四:如何用c++寫安卓手機軟體? 這個你不容易,安卓是java寫的,你學過C和C++想寫安卓軟體既需要學java語言,又需要學安卓手機的介面,相當於新學,不天天學兩三年寫不出什麼東西的。建議寫個win7能用的加殼程序,現在的殼基本上是以前系統上的,win7實用的不多。

問題五:怎樣編寫安卓手機程序???用什麼軟體編寫 。 說具體點 。 樓主看一下這個教程,或許能幫到您。 pan./...703809

問題六:怎樣將自己寫的程序放到android手機里運行 你是用ECLIPSE開發的程序吧?
如果是的話可以先USB接上手機和電腦,手機打開調試模式然後直接在項目上右鍵 -伐> 運行方式 -- > android application 可以直接運行
APK文件的話在項目的BIN目錄下面

問題七:安卓軟體怎麼寫 寫安卓程序的話有好多平台,常用的就是eclipse和myeclipse,我場做安卓開發都是用這兩個平台。安裝起來也方便,當然,如果您的水平高的話可以直接記事本寫代碼再編譯。。。

問題八:安卓開發軟體歡迎界面怎麼做 顯示一個載入的界面,增加一個延時任務。比如用handler,幾秒後再執行跳轉到主界面。

問題九:如何學習安卓軟體開發 200分 你把android sdk中的開發文檔下載到本地,然後eclipse中就有javadoc顯示了,你就能在代碼里看到每個庫函數的用法了。書的話我建議買 精通Android2 ,或者 Android2高級編程 這兩本書,講解的細致,但是一定要結合sdk來看。國內的不要買。。。。(切身體會,千萬別買)看完之後就可以自己動手做做項目了。對於java基礎,我現在的感覺是 如果要深入學習android平台,java基礎一定要好(里邊包括各種java類庫的用法,本地代碼jni什麼的)。但如果平時隨便做做應用的話,會面向對象編程就完全可以了。

G. Android開發之ImageView播放GIF動畫實例

Android開發之ImageView播放GIF動畫實例

Android的原生控制項並不支持播放GIF格式的圖片,如果想在Android中顯示一張GIF動態圖片,可以利用 ImageView控制項來完成,但是放進去之後,你會發現,ImageView它只會顯示這張圖片的第一幀,不會產生任何的動畫效果。我們必須通過自定義控制項的方式來實現ImageView播放GIF 圖片的功能。

首先我們來編寫一個PowerImageView控制項,讓它既能支持ImageView控制項原生的所有功能,同時還可以播放GIF動態圖片。

先新建一個項目PowerImageViewTest,這里使用Android 4.0+Eclipse。

由於是要自定義控制項,會需要一些自定義的控制項屬性,因此我們需要在values目錄下新建一個attrs.xml的文件,在這個文件中添加項目需要的自定義屬性。

這里我們目前暫時只需要一個自動播放auto_play屬性,XML文件代碼如下:

<?xml version="1.0" encoding="utf-8"?>

這個文件完成之後,下面我們來開始編寫主類PowerImageView類,由於PowerImageView類需要支持ImageView的所有功能,我們必須要讓PowerImageView繼承自ImageView,代碼如下:

public class PowerImageView extends ImageView implements OnClickListener {

/**

* 播放GIF動畫的關鍵類

*/

private Movie mMovie;

/**

* 開始播放按鈕圖片

*/

private Bitmap mStartButton;

/**

* 記錄動畫開始的時間

*/

private long mMovieStart;

/**

* GIF圖片的寬度

*/

private int mImageWidth;

/**

* GIF圖片的高度

*/

private int mImageHeight;

/**

* 圖片是否正在播放

*/

private boolean isPlaying;

/**

* 是否允許自動播放

*/

private boolean isAutoPlay;

/**

* PowerImageView構造函數。

*

* @param context

*/

public PowerImageView(Context context) {

super(context);

}

/**

* PowerImageView構造函數。

*

* @param context

*/

public PowerImageView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

/**

* PowerImageView構造函數,在這里完成所有必要的初始化操作。

*

* @param context

*/

public PowerImageView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PowerImageView);

int resourceId = getResourceId(a, context, attrs);

if (resourceId != 0) {

// 當資源id不等於0時,就去獲取該資源的流

InputStream is = getResources().openRawResource(resourceId);

// 使用Movie類對流進行解碼

mMovie = Movie.decodeStream(is);

if (mMovie != null) {

// 如果返回值不等於null,就說明這是一個GIF圖片,下面獲取是否自動播放的屬性

isAutoPlay = a.getBoolean(R.styleable.PowerImageView_auto_play, false);

Bitmap bitmap = BitmapFactory.decodeStream(is);

mImageWidth = bitmap.getWidth();

mImageHeight = bitmap.getHeight();

bitmap.recycle();

if (!isAutoPlay) {

// 當不允許自動播放的時候,得到開始播放按鈕的圖片,並注冊點擊事件

mStartButton = BitmapFactory.decodeResource(getResources(),R.drawable.start_play);

setOnClickListener(this);

}

}

}

}


@Override

public void onClick(View v) {

if (v.getId() == getId()) {

// 當用戶點擊圖片時,開始播放GIF動畫

isPlaying = true;

invalidate();

}

}


@Override

protected void onDraw(Canvas canvas) {

if (mMovie == null) {

// mMovie等於null,說明是張普通的圖片,則直接調用父類的onDraw()方法

super.onDraw(canvas);

} else {

// mMovie不等於null,說明是張GIF圖片

if (isAutoPlay) {

// 如果允許自動播放,就調用playMovie()方法播放GIF動畫

playMovie(canvas);

invalidate();

} else {

// 不允許自動播放時,判斷當前圖片是否正在播放

if (isPlaying) {

// 正在播放就繼續調用playMovie()方法,一直到動畫播放結束為止

if (playMovie(canvas)) {

isPlaying = false;

}

invalidate();

} else {

// 還沒開始播放就只繪制GIF圖片的第一幀,並繪制一個開始按鈕

mMovie.setTime(0);

mMovie.draw(canvas, 0, 0);

int offsetW = (mImageWidth - mStartButton.getWidth()) / 2;

int offsetH = (mImageHeight - mStartButton.getHeight()) / 2;

canvas.drawBitmap(mStartButton, offsetW, offsetH, null);

}

}

}

}


@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

if (mMovie != null) {

// 如果是GIF圖片則重寫設定PowerImageView的大小

setMeasuredDimension(mImageWidth, mImageHeight);

}

}


/**

* 開始播放GIF動畫,播放完成返回true,未完成返回false。

*

* @param canvas

* @return 播放完成返回true,未完成返回false。

*/

private boolean playMovie(Canvas canvas) {

long now = SystemClock.uptimeMillis();

if (mMovieStart == 0) {

mMovieStart = now;

}

int ration = mMovie.ration();

if (ration == 0) {

ration = 1000;

}

int relTime = (int) ((now - mMovieStart) % ration);

mMovie.setTime(relTime);

mMovie.draw(canvas, 0, 0);

if ((now - mMovieStart) >= ration) {

mMovieStart = 0;

return true;

}

return false;

}


/**

* 通過Java反射,獲取到src指定圖片資源所對應的id。

*

* @param a

* @param context

* @param attrs

* @return 返回布局文件中指定圖片資源所對應的id,沒有指定任何圖片資源就返回0。

*/

private int getResourceId(TypedArray a, Context context, AttributeSet attrs) {

try {

Field field = TypedArray.class.getDeclaredField("mValue");

field.setAccessible(true);

TypedValue typedValueObject = (TypedValue) field.get(a);

return typedValueObject.resourceId;

} catch (Exception e) {

e.printStackTrace();

} finally {

if (a != null) {

a.recycle();

}

}

return 0;

}


}

這個類的代碼注釋已經非常詳細了,我再來簡單地解釋一下。可以看到,我們重寫了ImageView中所有的構建函數,使得 PowerImageView的用法可以和ImageView完全相同。在構造函數中,則是對所有必要的數據進行了初始化操作。首先,我們調用了 getResourceId()方法去獲取圖片資源對應的id值,在getResourceId()方法內部是通過Java的反射機制來進行獲取的。得到了圖片資源的id後,我們將它轉換成InputStream,然後傳入到Movie.decodeStream()方法中以解碼出Movie對象。如果得到的Movie對象等於null,說明這是一張普通的圖片資源,就不再進行任何特殊處理,因為父類ImageView都幫我們處理好了。如果得到的 Movie對象不等於null,則說明這是一張GIF圖片,接著就要去獲取是否允許自動播放、圖片的寬高等屬性的值。如果不允許自動播放,還要給播放按鈕 注冊點擊事件,默認是不允許自動播放的。

接下來會進入到onMeasure()方法中。在這個方法中我們進行判斷,如果這是一張GIF圖片,則需要將PowerImageView的寬高重定義,使得控制項的大小剛好可以放得下這張GIF圖片。

再往後就會進入到onDraw()方法中。在這個方法里同樣先判斷當前是一張普通的圖片還是GIF圖片,如果是普通的圖片就直接調用 super.onDraw()方法交給ImageView去處理就好了。如果是GIF圖片,則先判斷該圖是否允許自動播放,允許的話就調用 playMovie()方法去播放GIF圖片就好,不允許的話則會先在PowerImageView中繪制該GIF圖片的第一幀,並在圖片上繪制一個播放 按鈕,當用戶點擊了播放按鈕時,再去調用playMovie()方法去播放GIF圖片。

下面我們來看看playMovie()方法中是怎樣播放GIF圖片的吧。可以看到,首先會對動畫開始的時間做下記錄,然後對動畫持續的時間做下記 錄,接著使用當前的時間減去動畫開始的時間,得到的時間就是此時PowerImageView應該顯示的那一幀,然後藉助Movie對象將這一幀繪制到屏 幕上即可。之後每次調用playMovie()方法都會繪制一幀圖片,連貫起來也就形成了GIF動畫。注意,這個方法是有返回值的,如果當前時間減去動畫 開始時間大於了動畫持續時間,那就說明動畫播放完成了,返回true,否則返回false。

完成了PowerImageView的編寫,下面我們就來看一看如何使用它吧,其實非常簡單,打開或新建activity_main.xml,代碼如下所示:

<relativelayout p=""

android:layout_width="match_parent"

android:layout_height="match_parent" >


<com.example.powerimageviewtest.powerimageview p=""

android:id="@+id/image_view"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:src="@drawable/anim"

/>


可以看到,PowerImageView的用法和ImageView幾乎完全一樣,使用android:src屬性來指定一張圖片即可,這里指定的anim就是一張GIF圖片。然後我們讓PowerImageView在布局裡居中顯示MainActivity中的代碼都是自動生成的,這里就不再貼出來了。在AndroidManifest.xml中還有一點需要注意,有些4.0 以上系統的手機啟動了硬體加速功能之後會導致GIF動畫播放不出來,因此我們需要在AndroidManifest.xml中去禁用硬體加速功能,可以通過指定android:hardwareAccelerated屬性來完成,代碼如下所示:

<?xml version="1.0" encoding="utf-8"?>

<manifest p=""

package="com.example.powerimageviewtest"

android:versionCode="1"

android:versionName="1.0" >


<uses-sdk p=""

android:minSdkVersion="14"

android:targetSdkVersion="17" />


android:allowBackup="true"

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme"

android:hardwareAccelerated="false"

>

android:name="com.example.powerimageviewtest.MainActivity"

android:label="@string/app_name" >


現在可以來運行一下代碼了,一打開程序你就會看到GIF圖片的第一幀,點擊圖片之後就可以播放GIF動畫了。

然後我們還可以通過修改activity_main.xml中的代碼,給它加上允許自動播放的屬性,代碼如下所示:

<relativelayout p=""

xmlns:attr="http://schemas.android.com/apk/res/com.example.powerimageviewtest"

android:layout_width="match_parent"

android:layout_height="match_parent" >


<com.example.powerimageviewtest.powerimageview p=""

android:id="@+id/image_view"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:src="@drawable/anim"

attr:auto_play="true"

/>


這里使用了剛才我們自定義的屬性,通過attr:auto_play來啟用和禁用自動播放功能。現在將auto_play屬性指定成true後,PowerImageView上就不會再顯示一個播放按鈕,而是會循環地自動播放動畫。不僅如此,PowerImageView還繼承了ImageView原生的所有功能,只要指定的不是GIF圖 片,PowerImageView表現的結果就和ImageView完全一致,現在我們來放一張普通的PNG圖片,修改 activity_main.xml中的代碼,如下所示:

<relativelayout p=""

android:layout_width="match_parent"

android:layout_height="match_parent" >


<com.example.powerimageviewtest.powerimageview p=""

android:id="@+id/image_view"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:src="@drawable/myphoto"

/>


這里在src屬性裡面指定了一張名字為myphoto的PNG圖片,圖片在布局正中央顯示出來了,正是普通ImageView所具備的功能。我們還可以在PowerImageView中指定android:scaleType等屬性,用法和原生的ImageView完全一樣。

閱讀全文

與android項目開發範例相關的資料

熱點內容
phpfpm進程池 瀏覽:791
解壓掏耳朵音頻 瀏覽:670
爬香山解壓 瀏覽:948
演算法導論回溯 瀏覽:339
開盤指標源碼查詢 瀏覽:526
有道雲保存伺服器出錯 瀏覽:639
生成360文件夾 瀏覽:1004
圖庫的文件夾是哪個 瀏覽:505
程序員為什麼葯學日語 瀏覽:423
熟悉linux常用命令 瀏覽:859
印度外賣小哥是程序員 瀏覽:413
紹興程序員開發駐場流程 瀏覽:546
索納塔8的壓縮比 瀏覽:16
私有雲主要伺服器 瀏覽:939
為什麼主題解壓那麼慢 瀏覽:862
怎麼下載掃描二維碼的手機app 瀏覽:728
雲伺服器創建私有鏡像的時候一定要關機嗎 瀏覽:115
php開發學習門戶 瀏覽:386
傳奇游戲伺服器怎麼設置 瀏覽:825
敲擊東西解壓完整版 瀏覽:401