Android 快傳 文件互傳

一個月沒有更新內容,因爲想要實踐一下自己的理論知識,於是參加了一個軟件類比賽,選題爲移動設備之間的文件互傳。
不得不說,實踐的確是鍛鍊解決問題能力的最好辦法。 遇到了很多自己在一般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上搜索,同樣可以找到。

WiFi P2P 官方文檔

《深入理解Android:Wi-Fi,NFC和GPS》章節連載[節選]–第七章 深入理解Wi-Fi P2P

Android平臺Wifi_Direct使用

5.文件傳輸:

文件傳輸方式,採用了與官方WiFiDirect demo中相同的socket方式。由於之前對通信相關的知識完全一點不瞭解,在這個過程中跌了無數坑,一路模仿着demo,查找着相關內容………..

socket起源於UNIX,在Unix一切皆文件哲學的思想下,socket是一種”打開—讀/寫—關閉”模式的實現,服務器和客戶端各自維護一個”文件”,在建立連接打開後,可以向自己文件寫入內容供對方讀取或者讀取對方內容,通訊結束時關閉文件。

基礎實現並不複雜,但是又很多可以擴展的,比如多線程,斷點傳輸……..
斷點傳輸查詢了一些信息,需要用到數據庫,對當前下載文件信息的的記錄….然而處於考試月並且ACM的省賽,區域賽需要準備,只能歸於未來完成計劃。

Socket的文檔:

簡單理解Socket

很詳細的例子Android 基於Socket的聊天室

最後採用的socket的單線程傳輸方式,因爲根據傳輸帶寬由取決於雙方的硬件,多線程下載只會使單個文件下載速度下降(不確定)。

官方demo中傳輸的文件類型唯一,並且傳輸文件名爲隨機時間命名。後查詢到採用包含文件信息的文件流解決問題。文件信息和文件合併後在寫入socket輸出流,從中獲取信息,先確定文件類型,再寫入相應文件。

基於TCP協議的文件傳輸,傳輸帶文件名等信息的文件流

6.下載信息更新:
通過Handler機制實現。在主線程中,對各個發送狀態進行監聽,相應的更新UI。在Socket通信過程中,不斷更新信息,發送信息。
參考了一些下載器demo的實現。

主要內部實現就是如上,但是隻是對於知識點的大概記錄,很多方面並沒有能夠完成依靠自己完成,僅僅知道學習,使用,模仿的程度,如果完全要求自己獨立完成,感覺還是比較吃力。已經完成的這部分,就已經相應再進行學習,掌握。
接下來會是對於軟件UI的實現記錄,主要使用的UI方式,例子。

一些人問的代碼分享
這個demo在github上的地址:https://github.com/lucky-code/Practice/tree/master/kuaichuan2.0

其次由於android6.0新的權限管理機制,這個demo需要補上一個權限申請,一個坑以後再填啦…..

發佈了68 篇原創文章 · 獲贊 23 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章