一個月沒有更新內容,因爲想要實踐一下自己的理論知識,於是參加了一個軟件類比賽,選題爲移動設備之間的文件互傳。
不得不說,實踐的確是鍛鍊解決問題能力的最好辦法。 遇到了很多自己在一般demo中,並沒有發現的問題,並且學習很多新的知識。
準備將這個Android實例的開發過程記錄。
軟件功能:
- 各類型文件的快速訪問
- 實現手機的文件的快速分享
- 通過電腦對於手機的文件訪問
主要技術:
1.文件閱覽:
已安裝APK軟件:
通過packageManager這個用於管理應用程序包,便能獲取已安裝程序的許多相應信息。具體到軟件中的實現參考了 郭霖 公衆號中推送的這篇仿QQ獲取手機中的APK並分享。
多媒體文檔以及office文檔:通過MediaStore的方式,根據相應文件類型的Uri來進行查找。MediaStore是android系統提供的一個多媒體數據庫,android中多媒體信息都可以從這裏提取。(MediaStore相應基礎知識)。
可以通過相應的SQL語句對數據進行查詢。如music則傳入
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
;
例PPT則爲
MediaStore.Files.getContentUri("external"),type
type爲查詢得的MIME類型
MediaStore.Files.FileColumns.MIME_TYPE==application/mspowerpoint
在按上面說明的Cursor,定義一個總的讀取數據的方式。
public synchronized List<TFile> getMediaFiles(Activity cxt , Uri uri,String select) { //TFile 爲一個總的文件管理類,包含文件的信息
Cursor mCursor = cxt.managedQuery(
uri,
new String[] {MediaStore.Audio.Media.DATA}, select,
null, " date_modified desc");
cxt.startManagingCursor(mCursor);
int count = mCursor.getCount();
if(count>0){
List<TFile> data = new ArrayList<TFile>();
if (mCursor.moveToFirst()) {
do {
TFile.Builder builder = new TFile.Builder(mCursor.getString(0));
TFile bxfile = builder.build();
if(null != bxfile&&bxfile.getFileSize()>819200)
data.add(bxfile);
} while (mCursor.moveToNext());
}
return data;
}else{
return null;
}
}
很大程度上學習了github上TracyZhangLei的FileExplorer,不僅僅是MediaStore,而是很多代碼上方式,設計模式,對整個工程上的框架的大體建立。
照片的顯示:通過ImageLoader對照片的加載,通過gridview的顯示。根據獲取的屏幕大小,調節Item的大小。這一塊自己寫的很失敗…..加載過程中總是各種問題不斷,最後還是參考了別人的代碼才完成。在照片的更新上的顯示還存在問題,每次都是對於listview的整體更新,體驗比較差,以後有時間修正。
文件閱覽的基本功能: 對當前文件夾遍歷,讀取文件夾下的文件信息,通過ListView的顯示。當時遇到的主要問題是,閱覽界面作爲一個Fragment,對於Activity的back鍵的監聽重載上,網上有很多種辦法,但是嘗試之後都遇到了問題,最後在Activity中回調函數的方式解決。2.電腦互傳:
搜索之後,發現有2種方式實現,一種是通過ftp協議實現,Android手機作爲數據傳輸過程中的ftp服務器;
一種是通過http協議實現。Android手機作爲數據傳輸過程中的http服務器。
在這篇Android基於WIFI實現電腦和手機間數據傳輸的技術方案研究中,對很多例子進行了說明。
最後選擇通過ftp協議的方式,採用Apache FtpServerFTP服務器引擎解決,這種方法的問題是需要的第三方jar包比較多,比較麻煩。參考了android 基於apache ftp server。
實現之後在同一WiFi網絡下,便可以通過相應的ftp地址對手機上的文件訪問。
熱點模式爲通過手機上的APWiFi,電腦與之相連接,同樣可以達到訪問的效果。
public boolean setWifiApEnabled(boolean enabled) { //熱點的開啓
WifiManager wifiManager = null;
wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (enabled) { // disable WiFi in any case
//wifi和熱點不能同時打開,所以打開熱點的時候需要關閉wifi
wifiManager.setWifiEnabled(false);
}
try {
//熱點的配置類
WifiConfiguration apConfig = new WifiConfiguration();
//配置熱點的名稱(可以在名字後面加點隨機數什麼的)
apConfig.SSID = "快傳";
final Myapplication Date = (Myapplication) getApplication();
if(Date.getName().equals("")){
apConfig.SSID = Date.getName();
}
//配置熱點的密碼
//通過反射調用設置熱點
Method method = wifiManager.getClass().getMethod(
"setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE);
ap_name.setText("用戶名");
ap_name.setVisibility(View.VISIBLE);
wifi_title.setText(" 連接電腦至本機熱點:");
//返回熱點打開狀態
return (Boolean) method.invoke(wifiManager, apConfig, enabled);
} catch (Exception e) {
return false;
}
}
3.藍牙分享:
很簡單的分享方式,通過手機中自帶的bluetooth,傳入相應的apk的URi地址,startActivity,便開始的文件的傳遞。
Intent intent_bluetooth = new Intent();
intent_bluetooth.setAction(Intent.ACTION_SEND);
intent_bluetooth.setType("*/*");
intent_bluetooth.setClassName("com.android.bluetooth", "com.android.bluetooth.opp.BluetoothOppLauncherActivity");
File f = new File("///data/app/com.wifidirect-1/base.apk");
intent_bluetooth.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
Log.d("ConnectFragment", "onItemLongClick: "+Uri.fromFile(f));
startActivity(intent_bluetooth);
在確定文件地址的過程中,從data/app中尋找相應文件。但是不確定是否有誤android版本的原因,顯示格式不再是查到的data/app + [包名]-N.apk(覆蓋安裝N次),而是data/app/包名-N/base.apk,並且在我多次覆蓋安裝後,N也並沒有發生變化,直接從該路徑讀取文件並沒有發生問題。
4.手機連接:
查詢到的連接方式有ad hoc模式和WiFiDirect模式。
QQ上的面對面快傳以及快牙 從使用上來說,感覺都是採用ad hoc模式,可能是因爲ad hoc設備支持比較廣,android2.3便可以使用,而WiFiDirect爲android4.0以上開始支持。並且從連接方式上,感覺ad hoc比較方便。而WiFiDirect的一些優點:強大的發現功能,如更高的數據速率、企業管理能力、WMM? Quality of Service模式,以及點到點連接的電源管理協議,安全性;在實際使用上,並沒有太大的體現。
但是由於找到的WiFiDirect的資料比較多,並且理論上WiFiDirect更爲優秀(WiFiDirect在使用中不會對正在使用WiFi網絡造成影響,ad hoc則必須斷開。)最後還是採用了WiFiDirect作爲了連接方式。
個人對其完全只能說是使用的程度,只能羅列自己在學習過程中查詢到的資料:
在sdk\samples\android-22\legacy\WiFiDirectDemo 中,可以看到官方的WiFiDriect的demo,雖然比較簡單,但是還是有比較大的幫助,在github上搜索,同樣可以找到。
《深入理解Android:Wi-Fi,NFC和GPS》章節連載[節選]–第七章 深入理解Wi-Fi P2P
5.文件傳輸:
文件傳輸方式,採用了與官方WiFiDirect demo中相同的socket方式。由於之前對通信相關的知識完全一點不瞭解,在這個過程中跌了無數坑,一路模仿着demo,查找着相關內容………..
socket起源於UNIX,在Unix一切皆文件哲學的思想下,socket是一種”打開—讀/寫—關閉”模式的實現,服務器和客戶端各自維護一個”文件”,在建立連接打開後,可以向自己文件寫入內容供對方讀取或者讀取對方內容,通訊結束時關閉文件。
基礎實現並不複雜,但是又很多可以擴展的,比如多線程,斷點傳輸……..
斷點傳輸查詢了一些信息,需要用到數據庫,對當前下載文件信息的的記錄….然而處於考試月並且ACM的省賽,區域賽需要準備,只能歸於未來完成計劃。
Socket的文檔:
很詳細的例子Android 基於Socket的聊天室
最後採用的socket的單線程傳輸方式,因爲根據傳輸帶寬由取決於雙方的硬件,多線程下載只會使單個文件下載速度下降(不確定)。
官方demo中傳輸的文件類型唯一,並且傳輸文件名爲隨機時間命名。後查詢到採用包含文件信息的文件流解決問題。文件信息和文件合併後在寫入socket輸出流,從中獲取信息,先確定文件類型,再寫入相應文件。
6.下載信息更新:
通過Handler機制實現。在主線程中,對各個發送狀態進行監聽,相應的更新UI。在Socket通信過程中,不斷更新信息,發送信息。
參考了一些下載器demo的實現。
主要內部實現就是如上,但是隻是對於知識點的大概記錄,很多方面並沒有能夠完成依靠自己完成,僅僅知道學習,使用,模仿的程度,如果完全要求自己獨立完成,感覺還是比較吃力。已經完成的這部分,就已經相應再進行學習,掌握。
接下來會是對於軟件UI的實現記錄,主要使用的UI方式,例子。
一些人問的代碼分享
這個demo在github上的地址:https://github.com/lucky-code/Practice/tree/master/kuaichuan2.0
其次由於android6.0新的權限管理機制,這個demo需要補上一個權限申請,一個坑以後再填啦…..