基于android的資源文件管理器
軟?件?學(xué)?院
畢業(yè)實訓(xùn)報告
課題名稱:?android資源管理器
專 業(yè):?軟件設(shè)計(游戲開發(fā)方向)
摘 要
相信大家對Android的發(fā)展歷史多少都有一些了解,Android曾經(jīng)是一家創(chuàng)立于舊金山的公司的名字,該公司于2005年8月份被Google收購,并從此踏上了飛速發(fā)展的道路。經(jīng)過這幾年的發(fā)展,它已經(jīng)發(fā)展成了一個平臺、一個生態(tài)體系?,F(xiàn)在Android在移動領(lǐng)域已經(jīng)得到了廣泛的應(yīng)用。根據(jù)Google于2011年6月份公布的數(shù)字,現(xiàn)在每天激活的Android設(shè)備高達(dá)50萬臺,比5月份的數(shù)據(jù)增加了10萬臺,Google還透露目前已經(jīng)與36家OEM廠商和215家運營商合作共激活了超過1億臺Android設(shè)備。
本文的軟件開發(fā)環(huán)境采用了Eclipse3.4 + Android SDK集成環(huán)境,編程語言采用了Java。
關(guān)鍵詞: Activity; Fragment;Service
目 錄
摘?要IIII
第1章?項目分析11
1.1 問題描述11
1.2技術(shù)分析11
1.2.1 Android四大組件11
1.2.2用戶界面22
1.2.3 Activity3
1.2.4 Fragment4
1.2.5 SQLite數(shù)據(jù)庫55
1.3工程進(jìn)度計劃66
第2章?系統(tǒng)需求分析77
2.1系統(tǒng)功能需求分析77
2.1.1文件系統(tǒng)的瀏覽77
2.1.2文件及文件夾得操作99
2.1.3文件系統(tǒng)安全管理1010
2.2 系統(tǒng)開發(fā)需求1010
2.2.1Android資源管理器的開發(fā)平臺1111
2.2.2Android開發(fā)框架1111
2.3操作系統(tǒng)及所需軟件需求1515
2.3.1 Android開發(fā)環(huán)境及變量配置1616
2.3.2 安裝配置JDK616JDK616JDK616
2.3.3 安裝配置SDK18SDK18SDK18
2.3.4 Eclipse的設(shè)置1818
2.3.5 Android版本配置1818
2.4系統(tǒng)非功能性需求1818
第3章?系統(tǒng)總體設(shè)計1919
3.1 基本框架與布局1919
3.1.1主界面ListView的實現(xiàn)1919
3.1.2 ListView監(jiān)聽事件2525
3.2 幫助與提示2727
3.2.1 幫助與提示的原理與實現(xiàn)2727
3.2.2 文件的讀取2929
3.2.3幫助與提示功能實現(xiàn)時遇到的問題及解決3030
3.3 文件打開的實現(xiàn)3131
3.3.1 判斷文件類型,分析打開方式3131
3.3.2 文件夾的打開3131
3.3.3 非文件夾類型文件的打開3333
3.3.4 效果圖示例示例:3838
3.3.5 在此功能實現(xiàn)過程中遇到的問題示例:3838
3.4 文件的復(fù)制,粘貼3939
3.4.2 此功能中遇到的問題4444
第4章 結(jié)束語4545
第1章 項目分析
基于Android手機的日益蓬勃發(fā)展,各種技術(shù)斷更新,智能機的大眾化走向,越來越多的繁瑣的文件出現(xiàn)在我們的手機上。因此,我們想要做一個Android資源管理系統(tǒng)來處理手機上的文件,讓用戶更好的使用手機。
1.1 問題描述
1.文件的各種操作功能的實現(xiàn)所遇到的問題
(1)文件(文件夾)的復(fù)制與粘貼(涉及IO流的操作)實現(xiàn)不了。
(2)文件(文件夾)的新建功能,目錄的新建一直有問題,不能達(dá)到預(yù)期的目標(biāo)。
(3)文件(文件夾)的搜索功能,關(guān)于搜索我們一直想實現(xiàn)搜索提示但是沒有實現(xiàn)。
(4)各種功能的使用,權(quán)限不夠問題、對文件夾進(jìn)行操作時,會彈出警告信號,甚至退出程序。
(5)文件夾的復(fù)制于文件的復(fù)制問題,只能實現(xiàn)文件的操作,不能對文件夾進(jìn)行操作
課題的研究總是伴隨著問題的出現(xiàn),問題總是要解決的,我們首先自己多多的實驗自己的想法,通過各種發(fā)放解決出現(xiàn)的問題,多方查閱資料,觀看視頻,并咨詢指導(dǎo)老師,從而解決出現(xiàn)的問題。
1.2技術(shù)分析
一句話概括Android應(yīng)用:基于Android系統(tǒng)的軟件開發(fā),語言基礎(chǔ)是java語言,通過控件的設(shè)置以及方法調(diào)用,實現(xiàn)一系列的功能,目前,Android系統(tǒng)的手機十分的火爆,因此我們準(zhǔn)備做一個基于Android手機的資源管理器。
1.2.1 Android四大組件
Android系統(tǒng)有四個重要的組件,分別是Activity、ServiceBroadcastReceiver和ContentProvider。
Activity是Android程序的曾憲曾,顯示可視化的用戶界面,并接受與用戶交互所產(chǎn)生的界面事件,與窗體的概念非常相似。Android一般啟動程序后會呈現(xiàn)一個Activity,用于提示用戶程序已經(jīng)正常啟動。Activity在界面的表現(xiàn)形式一般是全屏窗體,也可以是非全屏懸浮窗體或?qū)υ捒颉?/p>
Service一般用于沒有用戶界面,但是需要長時間在后臺運行的應(yīng)用。例如,在播放MP3音樂時,使用Service播放MP3音樂,可以在關(guān)閉播放器界面的情況下長時間的播放MP3音樂,并通過對外公開service的通信接口,控制MP3音樂的播放啟動、暫停和停止。
BroadcastReceiver是用來接收并響應(yīng)廣播消息的組件。大部分廣播消息是由系統(tǒng)產(chǎn)生的,例如失去改變、電量低或者語言選項改變等,但應(yīng)用程序也可以產(chǎn)生廣播消息,例如數(shù)據(jù)下載完畢等。BroadcastReceiver不包含任何用戶界面,但是可以通過啟動Activity或者Notification通知用戶接受到重要的消息。Notification能夠通過多種方法提示用戶,包括閃動背景燈、震動設(shè)備、發(fā)出聲音或在狀態(tài)欄上防止一個持久的圖標(biāo)等。
ContentProvider是Android系統(tǒng)提供的一種標(biāo)準(zhǔn)的數(shù)據(jù)共享機制,應(yīng)用程序可以通過ContentProvider訪問其他的應(yīng)用程序的私有數(shù)據(jù)。私有數(shù)據(jù)可以是存儲在文件系統(tǒng)中的文件,也可以是SQLite數(shù)據(jù)庫中的數(shù)據(jù)。Android系統(tǒng)內(nèi)部也提供一些內(nèi)置的ContentProvider,能夠用為應(yīng)用程序提供重要的數(shù)據(jù)信息,例如聯(lián)系人的信息和通話記錄等。
1.2.2用戶界面
Android系統(tǒng)的界面空間分為定制控件。定制空間是用戶獨立開發(fā)的空間,或者通過繼承并修改系統(tǒng)空間后所產(chǎn)生的新空間,能夠提供特殊的功能和顯示需求。系統(tǒng)控件是Android系統(tǒng)中已經(jīng)封裝好的界面控件,而在代碼中動態(tài)修改需要更新狀態(tài)的界面元素。當(dāng)然,用戶也可以將所有的界面元素,無論在程序運行后是否需要修改其內(nèi)容,都放在代碼中進(jìn)行定義和聲明。很明顯這不是一種良好的界面設(shè)計模式,會給后期界面修改帶來不必要的麻煩,是應(yīng)用程序開發(fā)過程中最常見的功能控件。系統(tǒng)控件更有利于進(jìn)行快速開發(fā),同事能夠使Android應(yīng)用程序的界面保持一定的一致性。
常見的系統(tǒng)控件包括TextView、EditView、Button、ImageButton、CheckButton、Spinner、ListView和Tablehost。
界面布局(layout)是用戶界面結(jié)構(gòu)的描述,定義界面中所有的元素、結(jié)構(gòu)和相互關(guān)系。一般生命Android程序的界面布局有兩種方法,第一種是使用XML文件描述界面的布局,另一種是在程序運行時動態(tài)添加或修改界面布局。
Android系統(tǒng)在生命界面布局上提供了很好的靈活性,用戶既可以獨立使用任何一種聲明布局的方式,也可以同時使用兩種方式。一般情況下,使用XML文件來描述用戶界的基本元素,而在代碼中動態(tài)修改需要更新狀態(tài)的界面元素。當(dāng)然,用戶也可以將所有的界面元素,無論在程序運行后是否需要修改其內(nèi)容,都放在代碼中進(jìn)行定義和聲明。很明顯這不是一種良好的界面設(shè)計模式,會給后期界面修改帶來不必要的麻煩,而且界面較多時,程序代碼也會顯示凌亂不堪。
使用XML文件聲明界面布局,能夠更多地將程序的表現(xiàn)層和控制層分離,在修改界面時將不再需要更改程序的源代碼。
界面布局的種類:
(1).線性布局:線性布局(LinearLayout)是一種重要的界面布局,也是經(jīng)常使用的界面布局。在線性布局中,所有子元素都在垂直或水平方向按照順序在界面上排序。
(2).框架布局: 框架布局(FrameLayout)是最簡單的界面布局,用來存放一個元素的空白控件,且子元素的位置不能夠制定的,只能夠放置在空白空間的左上角。
(3) .表格布局:(TableLayout)也是一種常用的界面布局,它將屏幕劃分為表格,通過制定行和列可以將界面元素添加到表格中。
(4).相對布局:(RelativeLayout)是一種非常靈活的布局方式,能夠通過指定界面元素與其他元素的相對位置關(guān)系,確定界面中所有元素的布局為止。
(5).絕對布局:(AbsoluteLayout)能通過指定界面元素的坐標(biāo)文職,來確定用戶界面的整體布局。
1.2.3 Activity
Android中的一個Activity就是一個界面,比如說手機撥號界面,通訊錄界面等都是活動,在應(yīng)用程序中,可以有一個或多個活動,但是如果新建一個活動,必須要在AndroidMainfest.xml中聲明。
創(chuàng)建一個Activity需要注意的要點:
一個Activity就是一個類,并且這個類要繼承Activity;
需要復(fù)寫oncreate()方法
每一個Activity都是需要在android Mainfest.Xml文件中進(jìn)行配置
為Activity添加必要的控件
Activity 的生命周期
在Android開發(fā)中,Activity是非常重要的。Activity主要負(fù)責(zé)創(chuàng)建和顯示窗口,也可以把一個Activity理解成一個顯示的屏幕;在Android的應(yīng)用中不是僅有一個Activity,而是由很多個Activity存在。因其重要性,開發(fā)Android務(wù)必熟悉Activity生命周期,參照圖1.1。
onCreateView:Activity初次創(chuàng)建時被調(diào)用,一般在這里創(chuàng)建view,初始化布局信息,將數(shù)據(jù)綁定到list以及設(shè)置監(jiān)聽器等。如果Activity首次創(chuàng)建,本方法將會調(diào)用onStart();如果是停止后重新顯示,則將調(diào)用onRestart()。
onStart:當(dāng)Activity對用戶即將課件的時候被調(diào)用onResume()。
onRestart:當(dāng)Activity停止后重新顯示的時候被調(diào)用,然后調(diào)用onStart()。
onPause:當(dāng)系統(tǒng)要啟動一個其他的Activity時調(diào)用(其他的Activity顯示之前),這個方法使用來停止動畫和其他占用CPU資源的事情,所以這這里應(yīng)該保存那些持久數(shù)據(jù),這些數(shù)據(jù)可以在onResume()方法中讀出。
onStop:當(dāng)另一個Activity恢復(fù)并遮蓋住當(dāng)前Activity,導(dǎo)致其對用戶不再可見時調(diào)用,一個新的Activity啟動,其他Activity重新回到前景與用戶交互時會重新調(diào)用onResume(),如果Activity將退出則調(diào)用哦你D額story()。
onDestory:在當(dāng)前Activity被銷毀之前所調(diào)用的最后一個方法,當(dāng)進(jìn)程 終止前調(diào)用。
圖:1.1生命周期
1.2.4 Fragment
Fragment的主要目的在大屏幕設(shè)備上實現(xiàn)靈活的、動態(tài)的界面設(shè)計。例如,在Android的平板電腦上,因為屏幕有更多的空間來配置更多的組件,并且這些組件之間還會產(chǎn)生一定的數(shù)據(jù)交互。
Fragment支持這種設(shè)計理論,開發(fā)人員不需要管理復(fù)雜的試圖結(jié)構(gòu)變化,而且把這些動態(tài)的管理交給Fragment和回退堆棧(back stack)完成,在進(jìn)行界面設(shè)計時,只需要將界面布局按照功能和取于劃分為不同的模塊,每個模塊設(shè)計成一個Fragment即可。
Fragment具有和Activity類似的生命周期,但是比Activity支持更多的事件回調(diào)函數(shù)。Fragment生命周期中回調(diào)函數(shù),以及之間的調(diào)用順序可參照圖1.2。
創(chuàng)建Fragment
銷毀Fragment
onAttach()
onDetach()
onCreate()
onDistroyView()
onCreateView()
通過回退堆棧
onDestroyView()
onActivityCreateView()
onStart()
onStop()
onResume()
onPause()
Fragment處于活動狀態(tài)
1.2.5 SQLite數(shù)據(jù)庫
SQLite是一個2000年D.Richard Hipp發(fā)布的開源嵌入式關(guān)系數(shù)據(jù)庫。自從出現(xiàn)商業(yè)應(yīng)用程序依賴,數(shù)據(jù)庫就一直是應(yīng)用程序的主要組成部分,數(shù)據(jù)庫的管理系統(tǒng)也比較龐大和復(fù)雜,且會占用較多的系統(tǒng)資源。隨著嵌入式的應(yīng)用程序大量的出現(xiàn)。一種新型的輕量級數(shù)據(jù)庫SQLite也隨之產(chǎn)生。SQLite數(shù)據(jù)庫比傳統(tǒng)的數(shù)據(jù)庫更加適合用于嵌入式系統(tǒng),因為它占用資源少,運行高效可靠,可移植性強,并且提供了零配置運行模式。
1.3工程進(jìn)度計劃
表1.1 工程進(jìn)度計劃

第2章 系統(tǒng)需求分析
類似于PC中的資源管理器,手機文件管理器主要就是要起到手機文件系統(tǒng)與用戶之間溝通的橋梁作用,正確的反映文件系統(tǒng)的信息并為用戶方便高效地對系統(tǒng)文件的操作管理提供支持。應(yīng)用的研究目標(biāo)為針對手機應(yīng)用開發(fā)的特點。研究并設(shè)計一款滿足手機用戶文件系統(tǒng)瀏覽、文件操作管理、文件刪除、文件粘貼、文件復(fù)制等需求的手機應(yīng)用軟件,實現(xiàn)內(nèi)容包括系統(tǒng)的界面設(shè)計,與用戶之間的交互,內(nèi)部的操作流程,各個模塊之間的協(xié)同處理等,并最終成功運行于Android操作系統(tǒng)上。
2.1系統(tǒng)功能需求分析
從用戶的使用角度出發(fā),文件管理器的功能包括五個部分:文件瀏覽、文件操作管理、文件刪除、文件粘貼、文件復(fù)制。
2.1.1文件系統(tǒng)的瀏覽
文件管理器啟動后,將在主界面上顯示應(yīng)用主目錄信息所知路徑下的內(nèi)容,用戶也可以隨后在使用過程中對主目錄信息進(jìn)行修改和保存。用戶可以執(zhí)行目錄的跳轉(zhuǎn)操作,如選擇進(jìn)入當(dāng)前目錄的某一子目錄下,或者跳轉(zhuǎn)到當(dāng)前目錄的父目錄中,也可以在任意目錄下直接快速的跳轉(zhuǎn)到系統(tǒng)指定的主目錄下。
目錄跳轉(zhuǎn)的過程中要事先對路徑的有效性和用戶的權(quán)限進(jìn)行判斷。能夠正確判斷當(dāng)前顯示的路徑或要跳轉(zhuǎn)到的路徑在文件系統(tǒng)的狀態(tài),動態(tài)監(jiān)測因文件創(chuàng)建、刪除、SD卡的插入、移除等原因而導(dǎo)致的路徑變化情況并對界面進(jìn)行及時的刷新。非管理員用戶不能瀏覽系統(tǒng)關(guān)鍵路徑下的內(nèi)容。以免用戶的誤操作對系統(tǒng)文件造成破壞。從而導(dǎo)致手機的不能使用。
用戶可以設(shè)定在目錄跳轉(zhuǎn)的過程中是否對歷史路徑進(jìn)行保存,如果選擇保存,則在瀏覽的過程中按返回鍵后應(yīng)用將跳轉(zhuǎn)到前一個界面且可見位置與跳轉(zhuǎn)前保存一致,以此類推,知道返回至剛進(jìn)入應(yīng)用的目錄界面狀態(tài)后退出;如果選擇不保存,則在瀏覽的過程中按返回鍵直接推出。
另外,作為直接與用戶進(jìn)行交互的主界面,其形式標(biāo)準(zhǔn)也要進(jìn)行相互的規(guī)范。出于方便直觀的考慮,主界面采用列表的形式,每一個界面代表文件系統(tǒng)中一個文件夾下內(nèi)容,列表的每一行代表文件夾下的一個目錄項。對于文件夾,出于現(xiàn)實反應(yīng)速度考慮。以免用戶的誤操作對系統(tǒng)文件造成破壞。
每一行所顯示的信息只包括文件夾圖標(biāo)、文件夾名稱等。對于文件,顯示的信息包括文件類型圖形、文件名稱、文件的大小和修改時間等,對應(yīng)于不同類型的文件,需要有不同的圖標(biāo)與只對應(yīng)。在一般情況下每一行的左端還是需要一個觸發(fā)按鈕以供用戶對該文件方便的選取和應(yīng)用。如圖2.2所示
是 否
返回主界面
圖2.2 流程圖
2.1.2文件及文件夾得操作
文件管理器除了能夠在界面上對文件系統(tǒng)進(jìn)行正確的顯示,還要能夠為用戶提供各種文件操作的支持。具體操作類型和操作要求如表2.2所示。
表2.2 文件及文件夾操作

2.1.3文件系統(tǒng)安全管理
文針對當(dāng)前各種惡意軟件的威脅和用戶數(shù)據(jù)保護(hù)的需求,文件管理器還需要包含對文件系統(tǒng)安全管理的功能,能夠?qū)崟r的檢測文件系統(tǒng)中各種文件基本操作信息,包括文件打開、讀操作、寫操作、文件關(guān)閉等,并把相應(yīng)的進(jìn)程名和文件名以日志的方式記錄下來,提供給用戶查詢。作為文件管理器的高級功能,默認(rèn)于系統(tǒng)啟動后在后臺保持運行狀態(tài),用戶可以在文件管理器使用的過程中選擇停止或重新啟用該項功能,對信息的持久化要考慮到用戶手機應(yīng)用的特殊性。
2.2 系統(tǒng)開發(fā)需求
Android的應(yīng)用,開發(fā)采用了Java語言,所以它的學(xué)習(xí)曲線相對比較平緩。對于那些有一些編程語言,如C/C++/Java等,訓(xùn)練的學(xué)生,都可以考慮學(xué)習(xí)Android應(yīng)用開發(fā)。當(dāng)然,如果處于一個沒落的行業(yè),個人再努力,可能都趕不上整個行業(yè)墜落的速度。
如果你希望從事Android游戲開發(fā),那么,最好能在高數(shù)、離散數(shù)學(xué)甚至計算機圖形學(xué)等方面有比較扎實的基礎(chǔ)。如果后續(xù)想往底層開發(fā)如系統(tǒng)移植、驅(qū)動開發(fā)等方向發(fā)展,或者為了更好地理解Android 應(yīng)用架構(gòu)體系,那么,具備一定的操作系統(tǒng)知識是必要的當(dāng)然并不需要你對操作系統(tǒng)有多精通,而是對其基本原理有一定了解即可。系統(tǒng)中的應(yīng)用軟件依賴于不同的硬件平臺,不同的手機型號又對應(yīng)著不同的功能需求同事也要注意到,同一種軟件的主體功能還是相同的,知識某些方法少有差異,如何有效的管理眾多的版本代碼同事提高軟件的開發(fā)效率。
2.2.1Android資源管理器的開發(fā)平臺
文本Eclipse: Eclipse是一個開放源代碼的、基于 Java 的可擴(kuò)展開發(fā)平臺。就其本身言,它只是一個框架和一組服務(wù),用于通過插件組件構(gòu)建開發(fā)環(huán)境。幸運的是,附帶了一個標(biāo)準(zhǔn)的插件集,包括 Java 開發(fā)工具(Java Development Tools,JDT)。Eclipse是一個開放源代碼的軟件開發(fā)項目,專注于為高度集成的工具開發(fā)提供一個全功能的、具有商業(yè)品質(zhì)的工業(yè)平臺。
它主要由Eclipse項目、Eclipse工具項目和、Eclipse技術(shù)項目三個項目組成,具體包括四個部分組成——Eclipse Platform、JDT、CDT和PDE。JDT支持Java開發(fā)、CDT支持C開發(fā)、PDE用來支持插件開發(fā),Eclipse Platform則是一個開放的可擴(kuò)展IDE,提供了一個通用的開發(fā)平臺。它提供建造塊和構(gòu)造并運行集成軟件開發(fā)工具的基礎(chǔ)。Eclipse Platform允許工具建造者獨立開發(fā)與他人工具無縫集成的工具從而無須分辨一個工具功能在哪里結(jié)束,而另一個工具功能在哪里開始。
2.2.2Android開發(fā)框架
下面圖2.2是Android的體系架構(gòu)圖,自上而下分別為應(yīng)用層、應(yīng)用框架、類庫和Alvik運行時環(huán)境以及Linux內(nèi)核。

圖2.2 Android的體系架構(gòu)圖
一般來說,我們想從事Android開發(fā),可以從應(yīng)用開發(fā)作為切入點,逐漸熟悉其整個體系,并慢慢往其底層滲透,從而能做到軟硬兼?zhèn)洌珹ndroid系統(tǒng)開發(fā)班的課程設(shè)置就充分考慮到了這一點,既涉到應(yīng)用開發(fā)的透徹掌握,又幫助大家在系統(tǒng)開發(fā)層面上做好充分的準(zhǔn)備。而從學(xué)習(xí)的路線圖上來說,先熟悉Java SE編程,能比較熟練的使用Java語言進(jìn)行編程,熟悉Java語言語法特點,熟悉Java IO、Java線程、網(wǎng)絡(luò)編程、XML處理等。另外,因為很多的Android應(yīng)用在運行時都需要去訪問網(wǎng)站服務(wù)器,因此,熟悉一種網(wǎng)絡(luò)編程語言也是必要的。
無論是從開發(fā)班的課程設(shè)置就充分考慮到了這一點,既涉到應(yīng)用開發(fā)的透徹掌握,又幫助大家在系統(tǒng)開發(fā)層面上做好充分的準(zhǔn)備。而從學(xué)習(xí)的路線圖上來學(xué)習(xí)的方便性還是市場占有情況來說使用JSP/Servlet都是不二的選擇,另外,在這個階段也順便學(xué)習(xí)一下SQL語法和熟悉一種SQL數(shù)據(jù)庫,以方便后續(xù)Android開發(fā)中進(jìn)行SQLite數(shù)據(jù)庫開發(fā)。學(xué)習(xí)完這些課程后,就可以開始進(jìn)行Android的應(yīng)用開發(fā)的學(xué)習(xí),例如Android中的UI組件、基本組件、數(shù)據(jù)存儲、傳感器、圖形圖像處理、多媒體處理、游戲開發(fā)等。
Android包含一套C/C++庫,Android系統(tǒng)的各式組件都在使用。這些功能通過Android應(yīng)用框架暴露給開發(fā)人員。Android的核心類庫提供Java類庫所提供的絕大部分功能。每個Android應(yīng)用都運行在自己的進(jìn)程上,享有Dalvik虛擬機為它分配的專有實例。為了支持多個虛擬機在同一個設(shè)備上高效運行,Dalvik被改寫過。 Dalvik虛擬機執(zhí)行的是Dalvik格式的可執(zhí)行文件(.dex)該格式經(jīng)過優(yōu)化,以降低內(nèi)存耗用到最低。Java編譯器將Java源文件為class文件,class文件又被內(nèi)置的dx工具轉(zhuǎn)化為dex格式文件,這種文件在Dalvik虛擬機上注冊并運行。在一些底層功能——比如線程和低內(nèi)存管理方面,Dalvik虛擬機是依賴Linux內(nèi)核的。
為了更好地進(jìn)行應(yīng)用編程,可以有選擇的對其Lib類庫進(jìn)行分析,以加深對其工作機制的理解。再往下,就是操作系統(tǒng)層級了,這里應(yīng)該要對Linux操作系統(tǒng)進(jìn)行學(xué)習(xí),熟悉其內(nèi)核和運行原理,熟悉ARM體系架構(gòu)以及常用指令并熟悉驅(qū)動的編寫方式,掌握其移植方法等。Android的核心應(yīng)用程序就是依賴框架層次API開發(fā)的,程序員們可以充分使用這些API。應(yīng)用架構(gòu)設(shè)計的初衷是,簡化組件復(fù)用機制,任何應(yīng)用都能發(fā)布自己的功能,這些功能又可以被任何其他應(yīng)用使用,當(dāng)然要受來自框架的強制安全規(guī)范的約束。
每個Android應(yīng)用程序都存在于它自己的世界之中,默認(rèn)情況下,每個應(yīng)用程序均運行于它自己的Linux進(jìn)程中。當(dāng)應(yīng)用程序中的任意代碼開始執(zhí)行時,Android啟動一個進(jìn)程而當(dāng)不再需要此進(jìn)程而其它應(yīng)用程序又需要系統(tǒng)資源時,則關(guān)閉這個進(jìn)程。 每個進(jìn)程都運行于自己的Java虛擬機(VM)中。所以應(yīng)用程序代碼實際上與其它應(yīng)用程序的代碼是隔絕的。 默認(rèn)情況下,每個應(yīng)用程序均被賦予一個唯一的Linux用戶ID,并加以權(quán)限設(shè)置,使得應(yīng)用程序的文件僅對這個用戶、這個應(yīng)用程序可見。當(dāng)然,也有其它的方法使得這些文件同樣能為別的應(yīng)用程序所訪問。
Android應(yīng)用的構(gòu)成和工作流程如圖2.3:

圖2.3 Android的構(gòu)成
每個Android應(yīng)用程序都存在于它自己的世界之中,默認(rèn)情況下,每個應(yīng)用程序均運行于它自己的Linux進(jìn)程中。當(dāng)應(yīng)用程序中的任意代碼開始執(zhí)行時,Android啟動一個進(jìn)程而當(dāng)不再需要此進(jìn)程而其它應(yīng)用程序又需要系統(tǒng)資源時,則關(guān)閉這個進(jìn)程。每個進(jìn)程都運行于自己的Java虛擬機(VM)中。所以應(yīng)用程序代碼實際上與其它應(yīng)用程序的代碼是隔絕的。默認(rèn)情況下,每個應(yīng)用程序均被賦予一個唯一的Linux用戶ID,并加以權(quán)限設(shè)置,使得應(yīng)用程序的文件僅對這個用戶、這個應(yīng)用程序可見。當(dāng)然,也有其它的方法使得這些文件同樣能為別的應(yīng)用程序所訪問。
(l)應(yīng)用程序架構(gòu):在應(yīng)用程序架構(gòu)內(nèi)已經(jīng)具備多種不同的基礎(chǔ)組件,在開發(fā)應(yīng)用程序時,就可以直接調(diào)用這些組件來使用,可以節(jié)省開發(fā)應(yīng)用程序的心力及時間。
(2)Dalvik虛擬機器:在Android平臺上所使用Java虛擬機,不是Sim公司的標(biāo)準(zhǔn)Java虛擬機,而是使用Google自主開發(fā)的代號為Dalvik的虛擬機,它在保證API方面的兼容的同時,針對移動手機進(jìn)行了大幅優(yōu)化,占用資源更小,運行效率更高。
(3)集成的瀏覽器:集成的瀏覽器是Android內(nèi)建的瀏覽器,是以WebKit的瀏覽引擎為基礎(chǔ)所開發(fā)成的。WedKit是一個開源瀏覽器網(wǎng)頁排版引擎,目前使用WebKit引擎的瀏覽器主要有:Safari、Midori、Epiphany等。配合Android手機的功能,可以在瀏覽網(wǎng)頁時,達(dá)到更好的效果,例如:局部性的縮放網(wǎng)頁上的資訊、觸控式的操作等效果。
(4)優(yōu)化的繪圖能力:在程序里可以用到的繪圖功能分為2D與3D兩個方面。在2D方面Android提供了一套特有的類庫(SGL;而在3D方面則是使用OpenGLES1.0(openGL for Embedded systems)規(guī)范的類庫。它們是一種非??斓膱D形引擎,并且支持硬件加速。
(5)SQLite數(shù)據(jù)庫:SQLite提供結(jié)構(gòu)化的數(shù)據(jù)存取。SQLite是一款輕型的數(shù)據(jù)庫,它的設(shè)計目標(biāo)是嵌入式的,目前已經(jīng)在很多嵌入式產(chǎn)品中使用了它,它占用的資源非常低。它能夠支持Windows/Linux/U nix等主流的操作系統(tǒng),同時能夠跟很多程序語言相結(jié)合,比如:php、Java等,還有ODBC接口,同樣比起Mysql、PostgreSQL來講,它的處理速度比它們都快。它無需安裝和管理配置,它是一個儲存在單一磁盤文件中的完整數(shù)據(jù)庫,體積小只有250KB但支持?jǐn)?shù)據(jù)庫大小至2TB。它雖然很小巧,但是支持的SQL語句毫不遜色于其它開源數(shù)據(jù)庫。同時它還支持事務(wù)功能和并發(fā)處理等等。SQLite也是一套開放性的關(guān)聯(lián)式資料庫其特點在于輕量性方面的設(shè)計結(jié)構(gòu),更適合在手機上使用。
(6)多媒體的支持能力:主要用于播放媒體文件。這同時包括對音頻(如播放MP3或其他音樂文件等)和視頻(如播放從網(wǎng)上下載的視頻)的支持,并支持“播放URI地址”(Note:URI即是統(tǒng)一資源識別地址)模式—在網(wǎng)絡(luò)上直接播放的流媒體。另外支持各種通用的靜態(tài)圖像格式,例如:JPG、PNG、GIF等格式。
(7)GSM技術(shù):Global System for Mobile Communications,即全球移動通訊系統(tǒng),俗稱”全球通”,是一種起源于歐洲的移動通信技術(shù)標(biāo)準(zhǔn),是第二代移動通信技術(shù),其開發(fā)目的是讓全球各地可以共同使用一個移動電話網(wǎng)絡(luò)標(biāo)準(zhǔn),讓用戶使用一部手機就能行遍全球。GSM技術(shù)是屬于手機硬件方面的展現(xiàn),。它無需安裝和管理配置,它是一個儲存在單一磁盤文件中的完整數(shù)據(jù)庫,體積小只有250KB但支持?jǐn)?shù)據(jù)庫大小至2TB。它雖然很小巧,但是支持的SQL語句毫不遜色于其它開源數(shù)據(jù)庫。默認(rèn)情況下,每個應(yīng)用程序均運行于它自己的Linux進(jìn)程中。當(dāng)應(yīng)用程序中的任意代碼開始執(zhí)行時,Android啟動一個進(jìn)程而當(dāng)不再需要此進(jìn)程而其它應(yīng)用程序又需要系統(tǒng)資源時,則關(guān)閉這個進(jìn)程。每個進(jìn)程都運行于自己的Java虛擬機(VM)中。所以應(yīng)用程序代碼實際上與其它應(yīng)用程序的代碼是隔絕的。默認(rèn)情況下,每個應(yīng)用程序均被賦予一個唯一的Linux用戶ID,同時它還支持事務(wù)功能和并發(fā)處理等等也是在開發(fā)Android應(yīng)用程序時可以突出的特點之一。
(8)藍(lán)牙、EDGE、3G及Wi-Fi:藍(lán)牙是一種新型、開放、低成本、短距離的無線連接技術(shù)可取代短距離的電纜,實現(xiàn)話音和數(shù)據(jù)的無線傳輸。EDGE(Enhanced Data Rate for GSMEvolution),即增強型數(shù)據(jù)速率GSM演進(jìn)技術(shù)。EDGE是一種從GSM到3G的過渡技術(shù)它主要是在GSM系統(tǒng)中采用了一種新的調(diào)制方法,即最先進(jìn)的多時隙操作和SPSK調(diào)制技術(shù)。由于8PSK可將現(xiàn)有GSM網(wǎng)絡(luò)采用的GMSK調(diào)制技術(shù)的信號空間從2擴(kuò)展到8,從而使每個符號所包含的信息是原來的4倍。Wi-Fi(WirelessFidelity),即無線保真技術(shù),與藍(lán)牙技術(shù)一樣,是一種起源于歐洲的移動通信技術(shù)標(biāo)準(zhǔn),是第二代移動通信技術(shù),其開發(fā)目的是讓全球各地可以共同使用一個移動電話網(wǎng)絡(luò)標(biāo)準(zhǔn),讓用戶使用一部手機就能行遍全球。GSM技術(shù)是屬于手機硬件方面的展現(xiàn),這些通訊能力也是屬于手機硬件方面的展現(xiàn),也是在開發(fā)Android應(yīng)用程序時可以突出的特點之一。
(9)GPS: Global Positioning System,即全球定位系統(tǒng),它是一個由覆蓋全球的247 顆衛(wèi)星組成的衛(wèi)星系統(tǒng)。這個系統(tǒng)可以保證在任意時刻和任何地點都可以同時觀測到4顆衛(wèi)星,以保證衛(wèi)星可以采集到該觀測點的經(jīng)緯度和高度,以便實現(xiàn)導(dǎo)航、定位、授時等功能。這項技術(shù)可以用來引導(dǎo)飛機、船舶、車輛以及個人。這個同樣也是屬于手機硬體方面的體現(xiàn)也是在開發(fā)Android應(yīng)用程序是可以突出的特點之一
2.3操作系統(tǒng)及所需軟件需求
每個應(yīng)用程序均運行于它自己的Linux進(jìn)程中。當(dāng)應(yīng)用程序中的任意代碼開始執(zhí)行時,Android啟動一個進(jìn)程而當(dāng)不再需要此進(jìn)程而其它應(yīng)用程序又需要系統(tǒng)資源時,則關(guān)閉這個進(jìn)程。每個進(jìn)程都運行于自己的Java虛擬機(VM)中。所以應(yīng)用程序代碼實際上與其它應(yīng)用程序的代碼是隔絕的。默認(rèn)情況下,每個應(yīng)用程序均被賦予一個唯一的Linux用戶ID,并加以權(quán)限設(shè)置,使得應(yīng)用程序的文件僅對這個用戶、這個應(yīng)用程序可見。當(dāng)然,也有其它的方法使得這些文件同樣能為別的應(yīng)用程序所訪問。新下載好的Android源碼,只用配置好編譯的環(huán)境,在根目錄下執(zhí)行make命令,就可以生成系統(tǒng)鏡像,然后由Android模擬器加載并運行,對于實際圣餐中的源碼編譯來說,系統(tǒng)中的應(yīng)用軟件依賴于不同的硬件平臺,不同的手機型號又對應(yīng)著不同的功能需求同事也要注意到,同一種軟件的主體功能還是相同的,知識某些方法少有差異。
編寫Android的應(yīng)用程序,需要一套個人電腦系統(tǒng)。至于操作系統(tǒng)的部份,幾個主流操作系統(tǒng)都有支持。支持的操作系統(tǒng)如下,Windows XP 、Vista或Windows 7。
在開始搭建Android的開發(fā)環(huán)境之前,需要準(zhǔn)備的軟件包如下,
JDK6 (jdk-6u21-windows-i586.exe)
(2) Eclipse(eclipse-java-galileo-SR2-win32.zip)
(3) Android SDK 1.6(android-sdk-windows-1.6_r1.zip)
(4) Android SDK Setup(android-sdk_r06-windows.zip)
(5) ADT 0.9.7(ADT-0.9.7.zip)
2.3.1 Android開發(fā)環(huán)境及變量配置
Eclipse設(shè)計的美妙之處,在于所有東西都是外掛,除了底層的核心以外。這種外掛設(shè)計讓Eclipse具備強大擴(kuò)充性,但更重要的是,此平臺提供一個定義明確的機制,讓各種外
掛程序共通合作(透過延伸點extension points)與貢獻(xiàn)(contributions),因此新功能可以輕易且無縫地加入平臺。
2.3.2 安裝配置JDK6
下載后安裝是下的解壓包那就解壓到某目錄,例如解壓到是C:\Java\jdk1.6.0_20:右鍵點擊我的電腦 ->屬性 ->高級,點擊下面的環(huán)境變量,在下面的“系統(tǒng)變量”處選擇新建在變量名處輸入 JAVA_HOME變量值中輸入剛才的目錄,比如我的是在目錄
C:\Java\jdk1.6.0_20下,效果如圖2.4所示,

圖2.4進(jìn)入環(huán)境變量
確定后再新建一個變量名為CLASSPATH,變量值
為 %JAVA_HOME%/lib/rt.jar;%JAVA_HOME%/lib/tools.jar ,確定后找到Path的變量,雙擊或點擊編輯,在變量值最前面加上%JAVA_HOME%/tools; 注意里面的是。確定、確定、確定后即可。具體如下圖2.5所示,

圖 2.5環(huán)境變量的設(shè)置
接著在“開始->運行”,輸入cmd,然后在命令行提示符中輸入:java -version,如果能夠看到j(luò)ava version “1.6.0_20″信息就表示JDK安裝成功。
2.3.3 安裝配置SDK
將下載android-sdk-windows-1.6_r1.zip解壓縮到C:\android-sdk-windows-1.6_r1目錄中。新建一個“系統(tǒng)變量”,在“變量名”中填A(yù)ndroid_Home,在“變量值”加填C:\android-sdk-windows-1.6_r1?!熬庉嫛盤ATH變量,在“變量值”后面加上;%Android_Home%\tools。這樣,Android SDK 1.6就安裝好了?!伴_始->運行”,輸入cmd,
然后在命令行提示符中輸入:android -help,應(yīng)該能夠看到幫助信息:Android SDK 1.6安裝成功。
2.3.4 Eclipse的設(shè)置
將下載到的Eclipse解壓縮到C:\eclipse,然后進(jìn)入這個文件夾,雙擊eclipse.exe,啟動Eclipse。關(guān)聯(lián)Adnroid SDK菜單“Windows->Preferences”,打開Preferences對話框,點擊Android,在右側(cè)的Android Reference中,點SDK Location文本框右側(cè)的Browse?按鈕,找到C:\android-sdk-windows-1.6_r1,“確定”。安裝ADT菜單“Help -> InstallNew Software?”,打開Install對話框,點擊Add?按鈕,添加站點,Add Site,,在Name 中填A(yù)DT,在Location中填https://dl-ssl.google.com/android/eclipse/。然后,下載安裝ADT。第四步,解壓Android SDK Setup,下載更新Android SDK 2.0和2.1將下載到android-sdk_r04-windows.zip解壓縮到C:\android-sdk-windows,然后進(jìn)入這個文件夾,雙擊SDK Setup.exe,啟動Android SDK and AVD Manager,選中左側(cè)Settings項,然后在右側(cè)面板選中Force https://? sources to be fetched using http://,然后選擇Save & Apply。
2.3.5 Android版本配置
在Eclipse中,Window > Android SDK and AVD Manager,選擇左側(cè)Available Package,在右側(cè)Sites,Packages and Archives列表中勾選出SDK Platform Android 2.1, API 7revision 2和SDK Platform Android 2.2, API 8 revision 2,點擊界面右下方"Install Selected",開始升級至Android SDK 2.1和Android SDK 2.2。到此,在Windows下的Android2.2開發(fā)環(huán)境就搭建成功了。
2.4系統(tǒng)非功能性需求
1.文件管理器作為手機基本應(yīng)用的一部分,需要經(jīng)常與用戶進(jìn)行交互,其設(shè)計細(xì)節(jié)直接影響用戶的感受及工作效率,為了取得較好的效果,開發(fā)時需要注意以下幾點,文件管理器的整體風(fēng)格要與其他應(yīng)用保持一致,合理使用圖標(biāo)等輔助表達(dá)方式;合理規(guī)劃界面布局,優(yōu)化文件管理操作流程;操作前由用戶確認(rèn),操作后文用戶顯示結(jié)果,提供應(yīng)用幫助說明文檔。
2.文件管理器贏支持不同的硬件平臺上多分辨率顯示的情況,在相同的功能需求的前提下,一次開發(fā),多次利用。
3.文化管理器考慮到手機存儲資源的相對不足,對文件安全監(jiān)測的持久化信息進(jìn)行精簡,避免軟件運行帶來的不利影響。
4.文件管理器的設(shè)計應(yīng)具有可擴(kuò)展性,盡量提高硬件的無關(guān)性,要考慮到后續(xù)功能的變更情況,增強軟件的適應(yīng)能力。
5.新下載好的Android源碼,只用配置好編譯的環(huán)境,在根目錄下執(zhí)行make命令,就可以生成系統(tǒng)鏡像,然后由Android模擬器加載并運行,對于實際圣餐中的源碼編譯來說,系統(tǒng)中的應(yīng)用軟件依賴于不同的硬件平臺,不同的手機型號又對應(yīng)著不同的功能需求同事也要注意到,同一種軟件的主體功能還是相同的,知識某些方法少有差異,如何有效的管理眾多的版本代碼同事提高軟件的開發(fā)效率,是包括文件管理器在內(nèi)的整個系統(tǒng)開發(fā)與編譯過程中需要解決的問題。
第3章 系統(tǒng)總體設(shè)計
在本章中,將會對本文件管理器的部分功能進(jìn)行介紹,以下的幾個小節(jié)中會詳細(xì)的介紹的我在本應(yīng)用中承擔(dān)的部分工作以及實現(xiàn)的功能。其中主要介紹的功能有的布局實現(xiàn),文件的部分操作,如:文件粘貼、文件復(fù)制、幫助與提示界面的實現(xiàn),文件打開的實現(xiàn)等。
3.1 基本框架與布局
3.1.1主界面ListView的實現(xiàn)
在此程序中可視的基本框架主要有,剛進(jìn)入應(yīng)用的幫助與提示對話框,然后就是程序的主界面一個TextView來顯示文件當(dāng)前的地址,然后用一個ListView用列表的形式來顯示所有的File,最下面是一個GridView,來顯示手機、SD卡、搜索、創(chuàng)建、粘貼、退出這幾個功能,而這所得的控件主要是由一個布局文件main.xml提供的,main.xml布局文件如下:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/background">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/mPath"
android:textSize="20sp"
android:singleLine="true"></TextView>
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/mPath"
android:cacheColorHint="#00000000"
android:divider="@drawable/line"
android:layout_marginBottom="70px"></ListView>
<GridView
android:id="@+id/file_gridview_toolbar"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_alignParentBottom="true"></GridView>
</RelativeLayout>
效果圖如下:


圖 3-1 主界面效果圖01 圖 3-2 主界面效果圖02
控件的選擇:由于ListView可以一列表的形式顯示一個布局,所以在這里用此控件來作為文件的可視化組件,并且ListView的內(nèi)容是由一個布局文件list-child.xml實現(xiàn)的,list-child.xml的布局文件如下:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:gravity="left|center"
android:layout_height="38dp">
<ImageView
android:id="@+id/image_list_childs"
android:layout_height="40dip"
android:layout_width="40dip"></ImageView>
<TextView
android:id="@+id/text_list_childs"
android:layout_width="fill_parent"
android:textSize="20sp"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"></TextView>
</LinearLayout>
由于ListView是一個需要有適配器的組件所以要為其創(chuàng)建一個適配器來顯示List
View的內(nèi)容,因此就需要創(chuàng)建一個Adapter適配器FileAdapter讓其繼承BaseAdapter,然后是重寫B(tài)aseAdapter中的四個方法:getCount()、getItem()、getItemId()、getView(),并且實現(xiàn)這些方法。其中g(shù)etCount()的作用就是,這個ListView要顯示多少行,而這個行數(shù)有事傳過來的文件的子File個數(shù)Files,所以就要顯示files.length行。第二個方法的返回值就是,當(dāng)前ListView的第幾項。第四個方法才是重點,作用就是控制ListView顯示的內(nèi)容,再此方法中首先就要獲取一個布局文件并轉(zhuǎn)化為一個View,然后通過為View中的兩個控件ImageView和TextView設(shè)置內(nèi)容來讓ListView顯示出來。
Adapter部分源碼:
/**自定義Adapter內(nèi)部類*/
class FileAdapter extends BaseAdapter{
private Bitmap mBackRoot;private Bitmap mBackUp;private Bitmap mImage;private Bitmap mAudio;private Bitmap mRar;
private Bitmap mVideo;private Bitmap mFolder;private Bitmap mApk;private Bitmap mOthers;private Bitmap mTxt;private Bitmap mWeb;
private Context mContext;private List<String> mFileNameList;private List<String> mFilePathList;
public FileAdapter(Context context,List<String> fileName,List<String> filePath){
mContext = context;
mFileNameList = fileName;
mFilePathList = filePath;
mBackRoot = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.back_to_root);
mBackUp = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.back_to_up);
mImage = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.image);
/****不同文件類型的圖片加載代碼塊****/
}
public int getCount() {
return mFilePathList.size();
}
public Object getItem(int position) {
return mFileNameList.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup viewgroup) {
ViewHolder viewHolder = null;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater mLI = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = mLI.inflate(R.layout.list_child, null);
viewHolder.mIV = (ImageView)convertView.findViewById(R.id.image_list_childs);
viewHolder.mTV = (TextView)convertView.findViewById(R.id.text_list_childs);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
File mFile = new File(mFilePathList.get(position).toString());
if(mFileNameList.get(position).toString().equals("BacktoRoot")){
viewHolder.mIV.setImageBitmap(mBackRoot);
viewHolder.mTV.setText("返回根目錄");
}else if(mFileNameList.get(position).toString().equals("BacktoUp")){
viewHolder.mIV.setImageBitmap(mBackUp);
viewHolder.mTV.setText("返回上一級");
}else if(mFileNameList.get(position).toString().equals("BacktoSearchBefore")){
viewHolder.mIV.setImageBitmap(mBackRoot);
viewHolder.mTV.setText("返回搜索之前目錄");
}else{
/***(文件圖標(biāo)設(shè)置代碼塊)***/
}
return convertView;
}
class ViewHolder {
ImageView mIV;
TextView mTV;
}
}
由于文件的類型有很多樣如:txt、Pdf、html、chm、mp4、mp3等,所以每種類型的文件也要配上不同的圖標(biāo)這樣才便于觀看和查找,所需要的文件。而在此程序中每個類型的文件使用的是同一種圖標(biāo),例如:mp3、wav等音樂格式為一種,mp4、3GP、flv、rmvb等視頻格式為一種,gif、jpg、png等圖片格式為一種,html等網(wǎng)頁格式為一種還有其他的好多的類型。所以在上邊的代碼中的圖片加載區(qū)中的代碼是對每種類型的圖標(biāo)進(jìn)行加載的,部分源代碼如下:
mAudio = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.audio);
mVideo = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.video);
mApk = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.apk);
mTxt = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.txt);
mOthers = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.others);
mFolder = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.folder);
mRar = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.zip_icon);
mWeb = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.web_browser);
mAudio = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.audio);
mVideo = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.video);
mApk = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.apk);
mTxt = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.txt);
mOthers = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.others);
mFolder = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.folder);
mRar = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.zip_icon);
mWeb = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.web_browser);
而每種文件圖標(biāo)的設(shè)置原理是根據(jù)文件的后綴名字來確定的,例如文件的后綴名判斷為fileEnds.equals("jpg")||fileEnds.equals("gif")||fileEnds.equals("png")||fileEnds.equals
("jpeg")||fileEnds.equals("bmp"),則應(yīng)該顯示圖像類型的圖標(biāo),而且每一個類型的文件基本都需要判斷的,所以在上述代碼中的文件圖標(biāo)判斷區(qū)域的代碼應(yīng)該為,先對文件的名字進(jìn)行提取,提取方法為:首先用file.getName().lastIndexOf(".")判斷出最后一個點“.”出現(xiàn)的位置,因為在此“.”以后的字符串就是文件的擴(kuò)展名,即文件的類型。因為文件的擴(kuò)展名不包括“.”,所以file.getName().lastIndexOf(".")返回的Int類型的Index要加1,然后用substring(file.getName().lastIndexOf(".") + 1,file.getName().length())來獲取文件的后綴名,并用toLowerCase()方法把后綴名字全部改為小寫,之后就根據(jù)文件的擴(kuò)展名來判斷文件的類型。例如文件的后綴名字為影音類型end.equals("m4a")||end.equals("mp3")||end.
equals("mid")||end.equals("xmf")||end.equals("ogg")||end.equals("wav")){returngetAudioFileIntent (filePath);},根據(jù)判斷后的結(jié)果來分別顯示文件所應(yīng)該現(xiàn)實的圖標(biāo),具體的判斷方法如下:
String fileName = mFile.getName();
viewHolder.mTV.setText(fileName);
if(mFile.isDirectory()){
viewHolder.mIV.setImageBitmap(mFolder);
}else{
String fileEnds = fileName.substring(fileName.lastIndexOf(".")+1,fileName.length()).toLowerCase();//取出文件后綴名并轉(zhuǎn)成小寫
//判斷文件類型 選擇顯示的文件的圖標(biāo)
if(fileEnds.equals("m4a")||fileEnds.equals("mp3")||fileEnds.equals("mid")||fileEnds.equals("xmf")||fileEnds.equals("ogg")||fileEnds.equals("wav")){
viewHolder.mIV.setImageBitmap(mVideo);
}else if(fileEnds.equals("3gp")||fileEnds.equals("mp4")){
viewHolder.mIV.setImageBitmap(mAudio);
}else if(fileEnds.equals("jpg")||fileEnds.equals("gif")||fileEnds.equals("png")||fileEnds.equals("jpeg")||fileEnds.equals("bmp")){
viewHolder.mIV.setImageBitmap(mImage);
}else if(fileEnds.equals("apk")){
viewHolder.mIV.setImageBitmap(mApk);
}else if(fileEnds.equals("txt")){
viewHolder.mIV.setImageBitmap(mTxt);
}else if(fileEnds.equals("zip")||fileEnds.equals("rar")){
viewHolder.mIV.setImageBitmap(mRar);
}else if(fileEnds.equals("html")||fileEnds.equals("htm")||fileEnds.equals("mht")){
viewHolder.mIV.setImageBitmap(mWeb);
}else {
viewHolder.mIV.setImageBitmap(mOthers);
}
}
當(dāng)適配器中的所有內(nèi)容都準(zhǔn)備完畢后就開始為ListView來進(jìn)行設(shè)置了,只需要把當(dāng)前文件的所有子文件即Files傳遞到適配器對象中,然后受用ListView的的setAdapter方法把適配器對象傳遞進(jìn)去就可以了。
3.1.2 ListView監(jiān)聽事件
在ListView中有兩個監(jiān)聽事件,第一個就是onListItemClick事件,還有一個就是initItemLongClickListener事件。onListItemClick事件的作用就是代開文件或者文件夾,initItemLongClickListener的作用就是打開文件相關(guān)操作的對話框如圖3-3所示。
onListItemClick事件的功能:當(dāng)用戶點擊一個listView中的文件時,程序會判斷用戶點擊的文件在ListView中的位置Position,然后根據(jù)Position來判斷是哪個File,如果此File是文件夾則直接打開文件夾,然后刷新文件列表。如果是文件則直接調(diào)用openFile()方法來打開文件,onListItemClick方法內(nèi)容如下:
/**列表項點擊時的事件監(jiān)聽*/
@Override
protected void onListItemClick(ListView listView, View view, int position, long id){
final File mFile = new File(mFilePaths.get(position));
if(mFile.canRead()){//如果該文件是可讀的,我們進(jìn)去查看文件
if(mFile.isDirectory()){//如果是文件夾,則直接進(jìn)入該文件夾,查看文件目錄
initFileListInfo(mFilePaths.get(position));
}else{//如果是文件,則用相應(yīng)的打開方式打開
openFile(mFile);
}
}else{//如果該文件不可讀,我們給出提示不能訪問,防止用戶操作系統(tǒng)文件造成系統(tǒng)崩潰等
Toast.makeText(MainActivity.this, "對不起,您的訪問權(quán)限不足!", Toast.LENGTH_SHORT).show();
}
}
ListView中的另一個點擊事件initItemLongClickListener在此應(yīng)用的主要功能就是調(diào)出文件相關(guān)操作的對話框,其中對話框中有"復(fù)制","重命名","刪除","打開"四個選項,效果如圖3-3所示。而且在此對話框中也設(shè)置了按鍵監(jiān)聽事件,每個選項都有相應(yīng)的操作文件的方法。
initItemLongClickListener部分源碼如下:
/**長按文件或文件夾時彈出的帶ListView效果的功能菜單*/
private void initItemLongClickListener(final File file){
OnClickListener listener = new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int item) {//item的值就是從0開始的索引值(從列表的第一項開始)
if(file.canRead()){//注意,所有對文件的操作必須是在該文件可讀的情況下才可以,否則報錯
if(item == 0){//復(fù)制
Toast.makeText(MainActivity.this, "已復(fù)制!", Toast.LENGTH_SHORT).show();
isCopy = true;
mCopyFileName = file.getName();
mOldFilePath = mCurrentFilePath+java.io.File.separator+mCopyFileName;
}else if(item == 1){//重命名
initRenameDialog(file);
}else if(item == 2){//刪除
initDeleteDialog(file);
}else if(item==3){
openFile(file);
}
}else{
Toast.makeText(MainActivity.this, "對不起,您的訪問權(quán)限不足!", Toast.LENGTH_SHORT).show();
}
}
};
String[] mMenu = {"復(fù)制","重命名","刪除","打開"};
new AlertDialog.Builder(MainActivity.this)
.setTitle("請選擇操作!")
.setItems(mMenu, listener)
.setPositiveButton("取消",null).show()}

圖 3-3 initItemLongClickListener事件對話框
3.2 幫助與提示
3.2.1 幫助與提示的原理與實現(xiàn)
幫助與提示的原理就是利用一個單獨的布局在FE文件夾管理器運行行時首先跳出界面對用戶進(jìn)行提示, 幫助與提示的顯示原理是利用Dialog的子類AlretDialog來實現(xiàn)創(chuàng)建的的。
在AlretDialog顯示時用setTitle(“幫助和關(guān)于”)方法,為其設(shè)置Dialog標(biāo)題。用setMessage(String Text)方法為其設(shè)置文本內(nèi)容,而文本的內(nèi)容是調(diào)用getDocument(String fileName)方法,并且把文件的地址作為getDocument()方法的參數(shù)傳遞過去,在getDocument()方法中去讀取出文件的內(nèi)容然后返回到setMessage()中作為Dialog的內(nèi)容顯示出來。然后再用setPositiveButton()方法為其設(shè)置確定按鈕,而在setPositiveButton(String buttonName,OnClickListener on)方法中有兩個參數(shù),第一個參數(shù)為PositiveButton按鈕的顯示內(nèi)容,第二個參數(shù)為PositiveButton的OnClickListener點擊監(jiān)聽事件。
在為PositiveButton設(shè)置監(jiān)聽事件時由于此PositiveButton使用一次所以在這里的監(jiān)聽事件我用匿名內(nèi)部類來設(shè)置的監(jiān)聽事件,而且由于newPositiveButton不是button的子類所以在此處監(jiān)聽事件設(shè)置方法不是用view.View.OnClikListener()來設(shè)置監(jiān)聽方法而是用 DialogInterface.OnClickListener()來設(shè)置監(jiān)聽方法。
在此Dialog中由于調(diào)用時直接用的new方法,新建出來的,而不是在createDialog方法中創(chuàng)建,然后由showDialog(int number)調(diào)用顯示出來的,所以在AlertDialog的新建方法的最后必須用show()方法來讓其調(diào)用時就直接顯示出來,否則就會運行但是卻不顯示沒反應(yīng)也看不出來效果。
如下為代碼片段:
private void dialogOfHelpAndAbout(){
new AlertDialog.Builder(MainActivity.this)
.setTitle("幫助和關(guān)于")//設(shè)置Dialog的標(biāo)題
.setMessage(getDocument("txt/help_about.txt"))//讀取本地文件來顯示幫助和關(guān)于的內(nèi)容
.setPositiveButton("確定", new //設(shè)置確定按鈕及確定按鈕的按鍵響應(yīng)
DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int which){
initFileListInfo(mSDCard);
//一開始程序的時候加載手機目錄下的文件列
//表 mSDCard為file類型是指SD卡的的路徑名稱
}
}).show();
}
效果圖示例:

圖 3-4 幫助與提示對話框 圖 3-5 應(yīng)用的主界面
3.2.2 文件的讀取
在程序的文件提示與幫助中g(shù)etDocument(String mPath)方法的主要作用就是讀取本地assets文件夾下的“幫助和關(guān)于.txt”的文本中的內(nèi)容并用一個String字符串返回出去文本中的內(nèi)容。
在getDocument(String mPath)方法中有一個字符串類型的參數(shù)而此參數(shù)的作用就是傳遞過來“幫助和關(guān)于.txt”文本在assets文件夾下的地址路徑。而在讀取“幫助和關(guān)于.txt”文本的內(nèi)容時,使用的安卓系統(tǒng)自帶的getAssets().open(mPath)方法來讀取assets文件夾下的“幫助和關(guān)于.txt”文本。安卓系統(tǒng)自帶的getAssets().open(mPath)方法讀取后的返回值是一個InputStream類型的輸入流對象,然后再用此對象的reader(Byte[] bytes)方法來把文本中的內(nèi)容讀取出來。而在用到此對象的reader(Byte[] bytes)方法時,由于要把文本中的內(nèi)容讀取到一個Byte類型的數(shù)組里面,所以數(shù)組的大小應(yīng)該適當(dāng),否則就會造成系統(tǒng)資源的浪費。所以在為此數(shù)組的大小進(jìn)行設(shè)置時我用的是InputStream對象的available()方法來實現(xiàn),而此方法的作用就是讀取出文件的有效長度,再用此方法的返回值為byte數(shù)組設(shè)置長度,這樣就可以為讀取文件時來節(jié)約系統(tǒng)資源,提高性能。
如下為代碼片段:
/**讀取觀過程下assets文件夾中的"幫助和關(guān)于.txt"文檔*/
public String getDocument(String mPath){
// String mPath 傳進(jìn)來文件的地址
String mTxt = null;
try {
InputStream is = MainActivity.this.getAssets().open(mPath);
//安卓自帶的getAssets()方法讀取 Assets文件夾下的文件內(nèi)容
byte[] mByte = new byte[is.available()];
//為輸入流建立一個緩沖減少文件的讀寫頻率 起到緩沖作用 節(jié)約系統(tǒng)資源
//is.available() 有效字節(jié)數(shù) 有效長度
is.read(mByte); //文件內(nèi)容讀取到byte[] mByte中
mTxt = new String(mByte,"GB2312"); //顯示出來時的編碼
} catch (IOException e) {
e.printStackTrace();
}
return mTxt;
}
3.2.3幫助與提示功能實現(xiàn)時遇到的問題及解決
1、創(chuàng)建Dialog后沒有顯示
問題描述:
當(dāng)我寫好了dialogOfHelpAndAbout()方法,在方法中也用了new AlertDialog.Builder()方法創(chuàng)建玩Dialog對話框并且也為其設(shè)置好標(biāo)題、內(nèi)容、按鈕等一系列屬性時,我就在程序里面調(diào)用了此方法。但是結(jié)果卻是程序也能正常運行沒有報錯,但是彈出幫助與提示對話框那個階段沒有了,而且由于我在對話框的點擊事件中初始化的程序剛進(jìn)入時的界面,所以程序就一直是白屏!
問題的解決過程:
我還以為我沒有調(diào)用所以就去看看程序中,結(jié)果發(fā)現(xiàn)在onCreate()方法中已經(jīng)調(diào)用。所以我就知道運行了但是沒有顯示,因此我就在dialogOfHelpAndAbout()方法中用Log.(“debug”,”Dialog”)輸出調(diào)試了一下,而且程序再次運行時在LogCat中有我用Log輸出的內(nèi)容“Dialog”,所以我就知道了必定是我的創(chuàng)建的問題。然后就檢查了一下,發(fā)現(xiàn)Dialog方法中的show()方法沒有漏寫了,至此終于明白還是我的不認(rèn)真造成了此錯誤。
文件的讀取后發(fā)現(xiàn)只要是中文的就出現(xiàn)亂碼
問題描述:
我所有的在本地assets文件夾下的“幫助和關(guān)于.txt”的文本中的內(nèi)容,只要是中文,經(jīng)過讀取就會出現(xiàn)亂碼。
問題的解決過程:
由于這個問題以前我也曾遇到過,知道是編碼格式的不統(tǒng)一造成的,但是卻不知道怎么解決,于是就請教了指導(dǎo)老師,問老師這是怎么了.老師就對我說在String創(chuàng)建對象時,new String()方法中可傳遞兩個參數(shù),第一個是第一個可以是Byte[]數(shù)組,第二個參數(shù)就是字符編碼如:UTF-8、GB1312、GBK。。。。。。,因為我只寫了一個參數(shù),所以造成編碼格式的不統(tǒng)一了,因此就會出現(xiàn)亂碼了。最后在老師的指導(dǎo)下我把創(chuàng)建String對象的方法改為了:mTxt = new String(mByte,"GB2312"),這個問題就有順利的被解決了。
3.3 文件打開的實現(xiàn)
文件打開功能的原理是在此程序中,如果想要打開一個文件的話,要在lisview控件上點擊你想要打開的文件,程序會先在openFile()這個方法中判斷用戶點擊的是文件還是文件夾,如果這個文件是文件夾的話,則會調(diào)用打開文件夾的方法,如果點擊的文件的話,則調(diào)用打開文件的方法。
3.3.1 判斷文件類型,分析打開方式
當(dāng)用戶點擊一個listView中的文件時,程序會判斷用戶點擊的文件在ListView中的位置Position,然后根據(jù)Position來判斷是哪個File,之后就會調(diào)用openFiles()這個方法來把文件File傳遞過去,當(dāng)File傳遞到openFiles(File fiel)的時候,在openFile(File file)方法中,程序會首先判斷當(dāng)前操作的文件file的類型,用file.isDirectory()方法判斷傳過來的file是不是文件夾。
判斷文件代碼示例:
/**調(diào)用文件的打開方法,根據(jù)文件類型判斷文件的具體打開方法*/
private void openFiles(File file){
if(file.isDirectory()){
initFileListInfo(file.getPath());
}else{//如果是文件則調(diào)用文件的打開方法。
//隱式Intent跳轉(zhuǎn)
Intent openFileIntent = OpenFilePort.openFile(file.getPath());
startActivity(openFileIntent);
}
}
3.3.2 文件夾的打開
如果是文件夾則調(diào)用initFileListInfo(file.getPath())方法并把當(dāng)前文件夾的路徑傳遞過去,然后在initFileListInfo()方法中刷新文件列表。
刷新文件列表方法:
private void initFileListInfo(String filePath){
isAddBackUp = false;
mCurrentFilePath = filePath;
mPath.setText(filePath);
mFileName = new ArrayList<String>();
mFilePaths = new ArrayList<String>();
File mFile = new File(filePath);
File[] mFiles = mFile.listFiles();
//遍歷出該文件夾路徑下的所有文件/文件夾
if(menuPosition == 1&&!mCurrentFilePath.equals(mRootPath)){
initAddBackUp(filePath,mRootPath);
}else if(menuPosition == 2&&!mCurrentFilePath.equals(mSDCard)){
initAddBackUp(filePath,mSDCard);
}
/*將所有文件信息添加到集合中*/
for(File mCurrentFile:mFiles){
mFileName.add(mCurrentFile.getName());
mFilePaths.add(mCurrentFile.getPath());
}
/*適配數(shù)據(jù)*/
setListAdapter(new FileAdapter(MainActivity.this,mFileName,mFilePaths));
}
在initFileListInfo()方法中有一個參數(shù),即當(dāng)前點擊的文件,因為當(dāng)前操作的文件是文件夾才調(diào)用此方法,所以傳進(jìn)來的地址就是當(dāng)前操作的文件夾的地址。因為要顯示的文件夾列表就是當(dāng)前文件夾下的所有子文件,所以mFiles= mFile.listFiles(),然后便利所有的子文件并添加文件的路徑和文件的名字用兩個ArrayList集合來分別保存。再次方法中還有一個參數(shù)isAddBackUp,isAddbackUp=false的意思就是在文件列表的最上方是否添加返回上一層的按鈕,而且在這里設(shè)為false是為其初始化,在下面會用一個判斷方法initAddBackUp(參數(shù)一,參數(shù)二)來判斷此按鈕是否應(yīng)該顯示,其中第一個參數(shù)為當(dāng)前的文件夾的地址,即當(dāng)前現(xiàn)實的所有文件的父文件夾,第二個參數(shù)為系統(tǒng)的根目錄,然后用equals方法來判斷傳進(jìn)來的兩個文件地址是否一樣,如果一樣則不添加“返回根目錄”和“返回上一級”,如果不一樣即返回值為false則添加“返回根目錄”和“返回上一級”。
initAddBackUp()方法如下:
private boolean isAddBackUp = false;
/**根據(jù)點擊“手機”還是“SD卡”來加“返回根目錄”和“返回上一級”*/
private void initAddBackUp(String filePath,String phone_sdcard){
if(!filePath.equals(phone_sdcard)){
/*列表項的第一項設(shè)置為返回根目錄*/
mFileName.add("BacktoRoot");
mFilePaths.add(phone_sdcard);
/*列表項的第二項設(shè)置為返回上一級*/
mFileName.add("BacktoUp");
mFilePaths.add(new File(filePath).getParent());//回到當(dāng)前目錄的父目錄即回到上級
isAddBackUp = true;
}
3.3.3 非文件夾類型文件的打開
再點擊文件列表中的一個文件時,還有一種情況就是當(dāng)前操作的文件不是文件夾,即file.isDirectory()的返回值為false。那么這時就需要根據(jù)文件的名稱來判斷文件的打開方式,并把文件的打開方式顯示出來便于選擇,效果圖如下其中圖3-3為當(dāng)在文件列表中的文件長按點擊時所彈出的對話框,及其中的的功能,圖3-4為當(dāng)點擊mp3文件后的點擊事件所觸發(fā)的,文件打開方式所有關(guān)聯(lián)的播放軟件列表:

圖 3-6 文件的長按點擊事件對話框 圖 3-7 音頻文件的打開方式
文件打開方法部分源碼:
/**調(diào)用文件的打開方法,根據(jù)文件類型判斷文件的具體打開方法*/
private void openFiles(File file){
if(file.isDirectory()){
initFileListInfo(file.getPath());
}else{//如果是文件則調(diào)用文件的打開方法。
//隱式Intent跳轉(zhuǎn)
Intent openFileIntent = OpenFilePort.openFile(file.getPath());
startActivity(openFileIntent);
}
}
在以上方法中當(dāng)file.isDirectory的返回值為false時,就調(diào)用文件打開的工具類OpenFilePort中的openFile方法來判斷文件的具體打開方法,然后用隱式Intent來實現(xiàn)跳轉(zhuǎn),獲取文件的打開方法。在openFile()方法中首先要判斷此文件是否存在,如果不存在則直接返回為Null,不在跳轉(zhuǎn),如果存在,則繼續(xù)執(zhí)行。當(dāng)文件存在時首先要用file.getName()獲取文件的名字,然后根據(jù)當(dāng)前的文件名字來提取出文件的后綴名字,即文件的類型。獲取方法是:首先用file.getName().lastIndexOf(".")判斷出最后一個點“.”出現(xiàn)的位置,因為在此“.”以后的字符串就是文件的擴(kuò)展名,即文件的類型。因為文件的擴(kuò)展名不包括“.”,所以file.getName().lastIndexOf(".")返回的Int類型的Index要加1,然后用substring(file.getName().lastIndexOf(".") + 1,file.getName().length())來獲取文件的后綴名,并用toLowerCase()方法把后綴名字全部改為小寫,之后就根據(jù)文件的擴(kuò)展名來判斷文件的打開方法。例如文件的后綴名字為影音類型即end.equals("m4a")||end.equals("mp3")||end.equals("mid")||
end.equals("xmf")||end.equals("ogg")||end.equals("wav")){
return?getAudioFileIntent(filePath);}根據(jù)判斷后的結(jié)果來調(diào)用getAudioFileIntent(filePath)這個方法來實現(xiàn)影音文件的打開方式的關(guān)聯(lián)。
影音文件類型的文件getAudioFileIntent(filePath)方法示例:
public static Intent getAudioFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "audio/*");
return intent;
}
因為文件的類型有很多種所以判斷的方法也很多,一下為文件打開方式的部分示例:
public class OpenFilePort {
public static Intent openFile(String filePath){
File file = new File(filePath);
if(!file.exists()) return null;
/* 取得擴(kuò)展名 */
String end=file.getName().substring(file.getName().lastIndexOf(".") + 1,file.getName().length()).toLowerCase();
/* 依擴(kuò)展名的類型決定MimeType */
if(end.equals("m4a")||end.equals("mp3")||end.equals("mid")||
end.equals("xmf")||end.equals("ogg")||end.equals("wav")){
return getAudioFileIntent(filePath);
}else if(end.equals("3gp")||end.equals("mp4")){
return getAudioFileIntent(filePath);
}else if(end.equals("jpg")||end.equals("gif")||end.equals("png")||
end.equals("jpeg")||end.equals("bmp")){
return getImageFileIntent(filePath);
}else if(end.equals("apk")){
return getApkFileIntent(filePath);
}else if(end.equals("ppt")){
return getPptFileIntent(filePath);
}else if(end.equals("xls")){
return getExcelFileIntent(filePath);
}else if(end.equals("doc")){
return getWordFileIntent(filePath);
}else if(end.equals("pdf")){
return getPdfFileIntent(filePath);
}else if(end.equals("chm")){
return getChmFileIntent(filePath);
}else if(end.equals("txt")){
return getTextFileIntent(filePath,false);
}else{
return getAllIntent(filePath);
}
}
//Android獲取一個用于打開APK文件的intent
public static Intent getAllIntent( String param ) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri,"*/*");
return intent;
}
//Android獲取一個用于打開APK文件的intent
public static Intent getApkFileIntent( String param ) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri,"application/vnd.android.package-archive");
return intent;
}
//Android獲取一個用于打開VIDEO文件的intent
public static Intent getVideoFileIntent( String param ) {
Intent intent = new Intent("android.intent.action.VIEW");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "video/*");
return intent;
}
//Android獲取一個用于打開AUDIO文件的intent
public static Intent getAudioFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "audio/*");
return intent;
}
//Android獲取一個用于打開Html文件的intent
public static Intent getHtmlFileIntent( String param ){
Uri uri = Uri.parse(param ).buildUpon().encodedAuthority("com.android.htmlfileprovider").scheme("content").encodedPath(param ).build();
Intent intent = new Intent("android.intent.action.VIEW");
intent.setDataAndType(uri, "text/html");
return intent;
}
//Android獲取一個用于打開圖片文件的intent
public static Intent getImageFileIntent( String param ) {
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "image/*");
return intent;
}
//Android獲取一個用于打開PPT文件的intent
public static Intent getPptFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "application/vnd.ms-powerpoint");
return intent;
}
//Android獲取一個用于打開Excel文件的intent
public static Intent getExcelFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "application/vnd.ms-excel");
return intent;
}
//Android獲取一個用于打開Word文件的intent
public static Intent getWordFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "application/msword");
return intent;
}
//Android獲取一個用于打開CHM文件的intent
public static Intent getChmFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "application/x-chm");
return intent;
}
//Android獲取一個用于打開文本文件的intent
public static Intent getTextFileIntent( String param, boolean paramBoolean){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (paramBoolean){
Uri uri1 = Uri.parse(param );
intent.setDataAndType(uri1, "text/plain");
}else{
Uri uri2 = Uri.fromFile(new File(param ));
intent.setDataAndType(uri2, "text/plain");
}
return intent;
}
//Android獲取一個用于打開PDF文件的intent
public static Intent getPdfFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "application/pdf");
return intent;
}
}
3.3.4 效果圖示例示例:

圖3-8 手機根目錄 圖 3-9 手機SD卡根目錄
3.3.5 在此功能實現(xiàn)過程中遇到的問題示例:
遇到的問題:
1、文件的打開方式的關(guān)聯(lián)。
2、操作文件的地址間的傳遞
3、文件列表的刷新
解決過程:
文件的打開方式的關(guān)聯(lián):這是問的老師本來只會做出Txt文檔的打開,還是用的輸入輸出流然后讀取出文本中的內(nèi)容然后顯示到編輯框中。但后來問過老師才知道這種類似的文件打開方式還是有接口的,體統(tǒng)提供方法,直接用工具類就可以解決了。于是就在老師的幫助下,在網(wǎng)上找到了一段有關(guān)文件打開的工具類,就實現(xiàn)類文件的打開方式的鏈接。
文件操作的地址間的傳遞:在文件列表中的文件操作時,每當(dāng)有點擊事件時,都會有文件和文件地址間的傳遞。而在地址傳遞時要特別注意所操作的是哪個文件,一旦文件的地址或者文件傳遞錯誤,程序就會異常終止。
文件列表的刷新:每當(dāng)點擊文件列表中的文件夾時就會用到文件列表的刷新方法,而且每當(dāng)創(chuàng)建文件,或者文件夾時,也會要有文件的刷新操作。
3.4 文件的復(fù)制,粘貼
文件的復(fù)制和粘貼的原理就是,當(dāng)文件復(fù)制時用一個局部變量mOldFilePath把當(dāng)前操作的文件地址保存起來,當(dāng)粘貼時就會在新地址mNewFilePath中把,mOldFilePath所在的地址的文件,及其文件夾下的所有文件全部遍歷復(fù)制。
在此功能中最主要的就是文件的粘貼,而文件的復(fù)制的方法只是保存下文件的地址。
所以此功能的主要實現(xiàn)方法幾乎全部在文件的粘貼功能中。在文件的粘貼方法中,每當(dāng)點擊粘貼時就會產(chǎn)生新的當(dāng)前路徑粘貼路徑mNewFilePath,而新的粘貼路徑mNewFilePath有三個部分組成。第一部:分文件粘貼的地址是由當(dāng)前所在的文件夾,即當(dāng)前所顯示的所有文件的文件列表的父文件夾mCurrentFilePath。第二部分:為一個文件地址分隔符“/”,而此分割符的產(chǎn)生使用java中的方法java.io.File.separator來產(chǎn)生的,java.io.File.separator方法的主要作用就是,根據(jù)不同的系統(tǒng)來創(chuàng)建,符合當(dāng)前系統(tǒng)的文件分隔符。第三部分:在進(jìn)行復(fù)制操作時所操作的文件的名字,即mCopyFileName。新文件的產(chǎn)生必須要加上所復(fù)制的文件的名字,然后來創(chuàng)建所要復(fù)制的文件夾的同名文件夾。然后在此文件下進(jìn)行文件的復(fù)制操作。
文件的操作需要在不同的路徑下才可以進(jìn)行,因為用mOldFilePath.equals(mNew
FilePath)來判斷,復(fù)制操作時的文件路徑是否和粘貼的操作的文件路徑是否相同,不同則進(jìn)行后續(xù)的操作,相同則停止。而且每當(dāng)復(fù)制時就會把變量isCopy變?yōu)閠ure,即表示文件是允許復(fù)制的,且執(zhí)行了文件的復(fù)制操作。所以還要判斷isCopy是否為ture,如果為ture在可以進(jìn)行粘貼操作,否則就用Toast.makeText(MainActivity.this, "您還沒有\(zhòng)"復(fù)制\"某個文件,又或者您在當(dāng)前目錄下執(zhí)行了粘貼,這樣是不可以\"粘貼\"滴。",Toast.LENGTH_LONG).
show()方法發(fā)出一個提示,提示你不可以進(jìn)行粘貼操作。當(dāng)判斷后確定可以復(fù)制時,然后就進(jìn)行判斷文件夾是否存在,如果粘貼的位置有文件有復(fù)制的文件的存在,則用AlertDialog產(chǎn)生一個對話框,new AlertDialog.Builder(MainActivity.this).setTitle("提示!").setMessage("該文件名已存在,是否要覆蓋?").setPositiveButton("確定", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int which){
copyFile(mOldFilePath,mNewFilePath);
initFileListInfo(mCurrentFilePath);//刷新列表
}})在此對話空中會詢問是否覆蓋已經(jīng)存在的文件。如果點擊確定就會執(zhí)行copyFile(mOldFilePath,mNewFilePath)方法來進(jìn)行文件的復(fù)制操作,在復(fù)制之后也要進(jìn)行文件的刷新操作,否則新粘貼后文件或者文件夾是沒法立即顯示出來的。文件的復(fù)制及粘貼效果圖如下:

圖3-10 進(jìn)行復(fù)制的對話框 圖 3-11 錯誤粘貼命令提示

圖 3-12 同名文件覆蓋提示 圖 3-13 執(zhí)行復(fù)制后的提示
文件的的粘貼部分源碼:
private void palseFile(){
mNewFilePath = mCurrentFilePath+java.io.File.separator+mCopyFileName;//得到新路徑 ***要加上mCopyFileName復(fù)制文件的名字 不然只能復(fù)制源文件的內(nèi)容本文件夾沒有被復(fù)制
Log.d("copy", "mOldFilePath is "+mOldFilePath+"| mNewFilePath is "+mNewFilePath+"| isCopy is "+isCopy);
if(!mOldFilePath.equals(mNewFilePath)&&isCopy == true){//在不同路徑下復(fù)制才起效 注意isCopy為true
//iscopy是指 你已執(zhí)行了復(fù)制 不然只運行粘貼時沒有用的
if(!new File(mNewFilePath).exists()){//判斷粘貼的地址同級的文件中是否存在相同名字的文件夾 沒有則復(fù)制
copyFile(mOldFilePath,mNewFilePath);
Toast.makeText(MainActivity.this, "執(zhí)行了粘貼", Toast.LENGTH_SHORT).show();
initFileListInfo(mCurrentFilePath);
}else{
//Toast.makeText(MainActivity.this, "已存在該文件!", Toast.LENGTH_SHORT).show();
//存在相同文件則彈出對話框問是否覆蓋。。。。
new AlertDialog.Builder(MainActivity.this)
.setTitle("提示!")
.setMessage("該文件名已存在,是否要覆蓋?")
.setPositiveButton("確定", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int which){
copyFile(mOldFilePath,mNewFilePath);
initFileListInfo(mCurrentFilePath);//刷新列表
}
})
.setNegativeButton("取消", null).show();
}
}else{//如果沒有選則復(fù)制 直接粘貼就提示。。。
Toast.makeText(MainActivity.this, "您還沒有\(zhòng)"復(fù)制\"某個txt文本文件,又或者您在當(dāng)前目錄下執(zhí)行了粘貼,這樣是不可以\"粘貼\"滴。", Toast.LENGTH_LONG).show();//
}
}
復(fù)制方法copyFile(參數(shù)一,參數(shù)二)中第一個參數(shù)為文件的源地址,即要復(fù)制的文件的地址,第二個參數(shù)為目標(biāo)地址,即將要粘貼的文件的地址。在文件的復(fù)制方法中首先要判斷要復(fù)制的是文件還是文件夾,如果是文件則直接調(diào)用文件的復(fù)制方copyFiles(sourcePath, targetPath)并把源文件的地址和目標(biāo)的的地址傳遞過去,然后在copyFiles()中建立輸入輸出流,來實現(xiàn)文件的復(fù)制。如果是文件夾則首先遍歷此文件夾下的多有子File,然后再逐一判斷所有的子File,如果子File為文件則調(diào)用文件的復(fù)制方法,如果子File為文件夾則繼續(xù)遍歷,調(diào)用本方法。
/**復(fù)制方法*/
// copyFile()件的地址 目標(biāo)地址
public void copyFile(String sourcePath,String targetPath){
if(new File(sourcePath).isFile()){//是否是文件
//判斷文件的類型 是文件則直接復(fù)制
//File file=new File(targetPath+"/"+new File(sourcePath).getName());
copyFiles(sourcePath, targetPath);
}else{
//不是文件則創(chuàng)建文件夾
必須先創(chuàng)建文件夾 不然文件沒法粘貼進(jìn)去
new File(targetPath).mkdir();
遍歷源文件下的所有哦文件
File[] listFiles = new File(sourcePath).listFiles();
for (File file2 : listFiles) {
System.out.println("FIle2:"+file2.getName());
if(file2.isFile()){
//如果是文件類型則直接調(diào)用文件復(fù)制的方法
copyFiles(file2.getPath(), targetPath+"/"+file2.getName());
}
else{
String targetPath1=targetPath+"/"+file2.getName();
String sourcePath1=sourcePath+"/"+file2.getName();
/*傳過去地址 地址要注意 記得都加file.getname() 而且要改變成員變量sourcePath1,targetPath1的地址不然遍歷復(fù)制時只能復(fù)制當(dāng)前文件夾的下一層文件 沒在向深處遍歷*/
copyFile(sourcePath1, targetPath1);
}
}}
}
文件的復(fù)制方法copyFiles(String sourcePath, String targetPath)也有兩個參數(shù),中第一個參數(shù)為文件的源地址,即要復(fù)制的文件的地址,第二個參數(shù)為目標(biāo)地址,即將要粘貼的文件的地址。然后再此方法中主要是建立一個輸入流BufferedInputStream來讀取文件,然后還建立了一個輸出流BufferedOutputStream來粘貼文件進(jìn)行復(fù)制。
//文件的復(fù)制
private void copyFiles(String sourcePath, String targetPath) {
FileInputStream input = null;
BufferedInputStream inBuff = null;
BufferedOutputStream outBuff = null;
FileOutputStream output = null;
try {
input = new FileInputStream(sourcePath);
inBuff=new BufferedInputStream(input);
// 新建文件輸出流并對它進(jìn)行緩沖
output = new FileOutputStream(targetPath);
outBuff=new BufferedOutputStream(output);
// 緩沖數(shù)組
byte[] b = new byte[1024 * 5];
int len;
while ((len =inBuff.read(b)) != -1) {
outBuff.write(b, 0, len);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
// 刷新此緩沖的輸出流
try {
outBuff.flush();
//關(guān)閉流
inBuff.close();
outBuff.close();
output.close();