實(shí)現(xiàn)Android手機(jī)之間在局域網(wǎng)下傳輸任意文件設(shè)計(jì)報(bào)告_第1頁(yè)
實(shí)現(xiàn)Android手機(jī)之間在局域網(wǎng)下傳輸任意文件設(shè)計(jì)報(bào)告_第2頁(yè)
實(shí)現(xiàn)Android手機(jī)之間在局域網(wǎng)下傳輸任意文件設(shè)計(jì)報(bào)告_第3頁(yè)
實(shí)現(xiàn)Android手機(jī)之間在局域網(wǎng)下傳輸任意文件設(shè)計(jì)報(bào)告_第4頁(yè)
實(shí)現(xiàn)Android手機(jī)之間在局域網(wǎng)下傳輸任意文件設(shè)計(jì)報(bào)告_第5頁(yè)
已閱讀5頁(yè),還剩19頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

相比于通過(guò)WiifDirect進(jìn)行文件傳輸,通過(guò)Wifi熱點(diǎn)進(jìn)行設(shè)備配對(duì)更加方便,邏輯也更為直接,傳輸一個(gè)1G左右的壓縮包用了5分鐘左右的時(shí)間,平均傳輸速率有3.5M/S左右。此外,相對(duì)于上個(gè)版本,新版本除了提供傳輸進(jìn)度外,還提供了傳輸速率、預(yù)估完成時(shí)間、文件傳輸前后的MD5碼等數(shù)據(jù)實(shí)現(xiàn)的效果如下所示:開(kāi)啟Ap熱點(diǎn)接收文件連接Wiif熱點(diǎn)發(fā)送文件文件傳輸完成后校驗(yàn)文件完整性開(kāi)發(fā)步驟分為以下幾點(diǎn):在AndroidManifest中聲明相關(guān)權(quán)限(網(wǎng)絡(luò)和文件讀寫(xiě)權(quán)限)文件接收端開(kāi)啟Ap熱點(diǎn),作為服務(wù)器端建立Socket,在指定端口等待客戶端的連接文件發(fā)送端連接到Wifi熱點(diǎn),作為客戶端主動(dòng)連接到服務(wù)器端文件發(fā)送端將待發(fā)送的文件信息模型(包括文件路徑,文件大小和文件MD5碼等信息)通過(guò)Socket發(fā)送給文件接收端文件發(fā)送端發(fā)起實(shí)際的文件傳輸請(qǐng)求,接收端和發(fā)送端根據(jù)已接收到或已發(fā)送的的文件字節(jié)數(shù),計(jì)算文件傳輸進(jìn)度、文件傳輸速率和預(yù)估完成時(shí)間等數(shù)據(jù)文件傳輸結(jié)束后,對(duì)比文件信息模型攜帶來(lái)的MD5碼值與本地文件重新計(jì)算生成的MD5碼是否相等,以此校驗(yàn)文件完整性一、聲明權(quán)限本應(yīng)用并不會(huì)消耗移動(dòng)數(shù)據(jù),但由于要使用到Wifi以及JavaSocket,所以需要申請(qǐng)網(wǎng)絡(luò)相關(guān)的權(quán)限。此外,由于是要實(shí)現(xiàn)文件互傳,所以也需要申請(qǐng)SD卡讀寫(xiě)權(quán)限。<uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE"/><uses-permissionandroid:name="android.permission.CHANGE_WIFI_STATE"/><uses-permissionandroid:name="android.permission.CHANGE_NETWORK_STATE"/><uses-permissionandroid:name="android.permission.INTERNET"/><uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/>二、文件接收端文件接收端作為服務(wù)器存在,需要主動(dòng)開(kāi)啟Ap熱點(diǎn)供文件發(fā)送端連接,由于通過(guò)反射來(lái)開(kāi)啟熱點(diǎn)的方法在高版本系統(tǒng)上無(wú)法實(shí)現(xiàn),所以需要用戶主動(dòng)去開(kāi)啟熱點(diǎn),并設(shè)置固定的熱點(diǎn)名稱(chēng)此處需要先定義一個(gè)文件信息模型FileTransfer,F(xiàn)ileTransfer包含三個(gè)字段,MD5碼值用于校驗(yàn)文件的完整性,fileLength是為了用于計(jì)算文件的傳輸進(jìn)度和傳輸速率publicclassFileTransferimplementsSerializable{//文件路徑privateStringfilePath;//文件大小privatelongfileLength;//MD5碼privateStringmd5;···}Ap熱點(diǎn)開(kāi)啟成功后,就可以啟動(dòng)一個(gè)服務(wù)在后臺(tái)等待文件發(fā)送端來(lái)主動(dòng)連接了,這里使用IntentService在后臺(tái)監(jiān)聽(tīng)客戶端的Socket連接請(qǐng)求,并通過(guò)輸入輸出流來(lái)傳輸文件。此處的代碼比較簡(jiǎn)單,就只是在指定端口一直堵塞監(jiān)聽(tīng)客戶端的連接請(qǐng)求,獲取待傳輸?shù)奈募畔⒛P虵ileTransfer,之后就進(jìn)行實(shí)際的數(shù)據(jù)傳輸文件傳輸速率是每一秒計(jì)算一次,根據(jù)這段時(shí)間內(nèi)接收的字節(jié)數(shù)與消耗的時(shí)間做除法,從而得到傳輸速率,再通過(guò)將剩余的未傳輸字節(jié)數(shù)與傳輸速率做除法,從而得到預(yù)估的剩余傳輸時(shí)間@OverrideprotectedvoidonHandleIntent(Intentintent){if(intent!=null&&ACTION_START_RECEIVE.equals(intent.getAction())){clean();Filefile=null;Exceptionexception=null;try{serverSocket=newServerSocket();serverSocket.setReuseAddress(true);serverSocket.bind(newInetSocketAddress(Constants.PORT));Socketclient=serverSocket.accept();Log.e(TAG,"客戶端IP地址:"+client.getInetAddress().getHostAddress());inputStream=client.getInputStream();objectInputStream=newObjectInputStream(inputStream);fileTransfer=(FileTransfer)objectInputStream.readObject();Log.e(TAG,"待接收的文件:"+fileTransfer);if(fileTransfer==null){exception=newException("從文件發(fā)送端發(fā)來(lái)的文件模型為null");return;}elseif(TextUtils.isEmpty(fileTransfer.getMd5())){exception=newException("從文件發(fā)送端發(fā)來(lái)的文件模型不包含MD5碼");return;}Stringname=newFile(fileTransfer.getFilePath()).getName();//將文件存儲(chǔ)至指定位置file=newFile(Environment.getExternalStorageDirectory()+"/"+name);fileOutputStream=newFileOutputStream(file);startCallback();byte[]buf=newbyte[512];intlen;while((len=inputStream.read(buf))!=-1){fileOutputStream.write(buf,0,len);total+=len;}Log.e(TAG,"文件接收成功");stopCallback();if(progressChangListener!=null){//因?yàn)樯厦嬖谟?jì)算文件傳輸進(jìn)度時(shí)因?yàn)樾?shù)點(diǎn)問(wèn)題可能不會(huì)顯示到100%,所以此處手動(dòng)將之設(shè)為100%progressChangListener.onProgressChanged(fileTransfer,0,100,0,0,0,0);//開(kāi)始計(jì)算傳輸?shù)奖镜氐奈募腗D5碼progressChangListener.onStartComputeMD5();}}catch(Exceptione){Log.e(TAG,"文件接收Exception:"+e.getMessage());exception=e;}finally{FileTransfertransfer=newFileTransfer();if(file!=null&&file.exists()){transfer.setFilePath(file.getPath());transfer.setFileSize(file.length());transfer.setMd5(Md5Util.getMd5(file));Log.e(TAG,"計(jì)算出的文件的MD5碼是:"+transfer.getMd5());}if(exception!=null){if(progressChangListener!=null){progressChangListener.onTransferFailed(transfer,exception);}}else{if(progressChangListener!=null&&fileTransfer!=null){if(fileTransfer.getMd5().equals(transfer.getMd5())){progressChangListener.onTransferSucceed(transfer);}else{//如果本地計(jì)算出的MD5碼和文件發(fā)送端傳來(lái)的值不一致,則認(rèn)為傳輸失敗progressChangListener.onTransferFailed(transfer,newException("MD5碼不一致"));}}}clean();//再次啟動(dòng)服務(wù),等待客戶端下次連接startActionTransfer(this);}}}因?yàn)榭蛻舳丝赡軙?huì)多次發(fā)起連接請(qǐng)求,所以當(dāng)此處文件傳輸完成后(不管成功或失敗),都需要重新startService,讓服務(wù)再次堵塞等待客戶端的連接請(qǐng)求為了讓界面能夠?qū)崟r(shí)獲取到文件的傳輸狀態(tài),所以此處除了需要啟動(dòng)Service外,界面還需要綁定Service,所以需要用到一個(gè)更新文件傳輸狀態(tài)的接口publicinterfaceOnProgressChangListener{/*當(dāng)傳輸進(jìn)度發(fā)生變化時(shí)回調(diào)**@paramfileTransfer文件發(fā)送方傳來(lái)的文件模型*@paramprogress文件傳輸進(jìn)度*@paramspeed文件傳輸速率*@paramremainingTime預(yù)估的剩余完成時(shí)間*/voidonProgressChanged(FileTransferfileTransfer,intprogress,doublespeed,longremainingTime);//當(dāng)傳輸結(jié)束時(shí)voidonTransferFinished(FileTransferfileTransfer);}在界面層刷新UIprivateFileReceiverService.OnReceiveProgressChangListenerprogressChangListener=newFileReceiverService.OnReceiveProgressChangListener(){privateFileTransferoriginFileTransfer;@OverridepublicvoidonProgressChanged(finalFileTransferfileTransfer,finallongtotalTime,finalintprogress,finaldoubleinstantSpeed,finallonginstantRemainingTime,finaldoubleaverageSpeed,finallongaverageRemainingTime){this.originFileTransfer=fileTransfer;runOnUiThread(newRunnable(){@Overridepublicvoidrun(){if(isCreated()){progressDialog.setTitle("正在接收的文件:"+originFileTransfer.getFileName());if(progress!=100){progressDialog.setMessage("原始文件的MD5碼是:"+originFileTransfer.getMd5()+"\n\n"+"總的傳輸時(shí)間:"+totalTime+"秒"+"\n\n"+"瞬時(shí)-傳輸速率:"+(int)instantSpeed+"Kb/s"+"\n"+"瞬時(shí)-預(yù)估的剩余完成時(shí)間:"+instantRemainingTime+"秒"+"\n\n"+"平均-傳輸速率:"+(int)averageSpeed+"Kb/s"+"\n"+"平均-預(yù)估的剩余完成時(shí)間:"+averageRemainingTime+"秒");}progressDialog.setProgress(progress);progressDialog.setCancelable(true);progressDialog.show();}}});}@OverridepublicvoidonStartComputeMD5(){runOnUiThread(newRunnable(){@Overridepublicvoidrun(){if(isCreated()){progressDialog.setTitle("傳輸結(jié)束,正在計(jì)算本地文件的MD5碼以校驗(yàn)文件完整性");progressDialog.setMessage("原始文件的MD5碼是:"+originFileTransfer.getMd5());progressDialog.setCancelable(false);progressDialog.show();}}});}@OverridepublicvoidonTransferSucceed(finalFileTransferfileTransfer){runOnUiThread(newRunnable(){@Overridepublicvoidrun(){if(isCreated()){progressDialog.setTitle("傳輸成功");progressDialog.setMessage("原始文件的MD5碼是:"+originFileTransfer.getMd5()+"\n"+"本地文件的MD5碼是:"+fileTransfer.getMd5()+"\n"+"文件位置:"+fileTransfer.getFilePath());progressDialog.setCancelable(true);progressDialog.show();Glide.with(FileReceiverActivity.this).load(fileTransfer.getFilePath()).into(iv_image);}}});}@OverridepublicvoidonTransferFailed(finalFileTransferfileTransfer,finalExceptione){runOnUiThread(newRunnable(){@Overridepublicvoidrun(){if(isCreated()){progressDialog.setTitle("傳輸失敗");progressDialog.setMessage("原始文件的MD5碼是:"+originFileTransfer.getMd5()+"\n"+"本地文件的MD5碼是:"+fileTransfer.getMd5()+"\n"+"文件位置:"+fileTransfer.getFilePath()+"\n"+"異常信息:"+e.getMessage());progressDialog.setCancelable(true);progressDialog.show();}}});}};三、文件發(fā)送端文件發(fā)送端作為客戶端存在,需要主動(dòng)連接文件接收端開(kāi)啟的Wifi熱點(diǎn)/*連接指定Wifi**@paramcontext上下文*@paramssidSSID*@parampassword密碼*@return是否連接成功*/publicstaticbooleanconnectWifi(Contextcontext,Stringssid,Stringpassword){StringconnectedSsid=getConnectedSSID(context);if(!TextUtils.isEmpty(connectedSsid)&&connectedSsid.equals(ssid)){returntrue;}openWifi(context);WifiConfigurationwifiConfiguration=isWifiExist(context,ssid);if(wifiConfiguration==null){wifiConfiguration=createWifiConfiguration(ssid,password);}WifiManagerwifiManager=(WifiManager)context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);if(wifiManager==null){returnfalse;}intnetworkId=wifiManager.addNetwork(wifiConfiguration);returnwifiManager.enableNetwork(networkId,true);}/*開(kāi)啟Wifi**@paramcontext上下文*@return是否成功*/publicstaticbooleanopenWifi(Contextcontext){WifiManagerwifiManager=(WifiManager)context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);returnwifiManager!=null&&(wifiManager.isWifiEnabled()||wifiManager.setWifiEnabled(true));}/*獲取當(dāng)前連接的Wifi的SSID**@paramcontext上下文*@returnSSID*/publicstaticStringgetConnectedSSID(Contextcontext){WifiManagerwifiManager=(WifiManager)context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);WifiInfowifiInfo=wifiManager==null?null:wifiManager.getConnectionInfo();returnwifiInfo!=null?wifiInfo.getSSID().replaceAll("\"",""):"";}連接到指定Wifi后,在選擇了要發(fā)送的文件后,就啟動(dòng)一個(gè)后臺(tái)線程去主動(dòng)請(qǐng)求連接服務(wù)器端,然后就是進(jìn)行實(shí)際的文件傳輸操作了demo提供的例子是只用來(lái)傳輸圖片,但理論上是可以傳輸任意格式的文件的privatevoidnavToChose(){Matisse.from(this).choose(MimeType.ofImage()).countable(true).showSingleMediaType(true).maxSelectable(1).capture(false).captureStrategy(newCaptureStrategy(true,BuildConfig.APPLICATION_ID+".fileprovider")).restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED).thumbnailScale(0.70f).imageEngine(newGlide4Engine()).forResult(CODE_CHOOSE_FILE);}獲取選取的文件的實(shí)際路徑,并啟動(dòng)FileSenderService去進(jìn)行文件傳輸操作@OverrideprotectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){super.onActivityResult(requestCode,resultCode,data);if(requestCode==CODE_CHOOSE_FILE&&resultCode==RESULT_OK){List<String>strings=Matisse.obtainPathResult(data);if(strings!=null&&!strings.isEmpty()){Stringpath=strings.get(0);Filefile=newFile(path);if(file.exists()){FileTransferfileTransfer=newFileTransfer(file);Log.e(TAG,"待發(fā)送的文件:"+fileTransfer);FileSenderService.startActionTransfer(this,fileTransfer,WifiLManager.getHotspotIpAddress(this));}}}}將服務(wù)器端的IP地址作為參數(shù)傳給FileSenderService,在正式發(fā)送文件前,先發(fā)送包含文件信息的FileTransfer,并在發(fā)送文件的過(guò)程中實(shí)時(shí)更新文件傳輸狀態(tài)@OverrideprotectedvoidonHandleIntent(Intentintent){if(intent!=null&&ACTION_START_SEND.equals(intent.getAction())){clean();fileTransfer=(FileTransfer)intent.getSerializableExtra(EXTRA_PARAM_FILE_TRANSFER);StringipAddress=intent.getStringExtra(EXTRA_PARAM_IP_ADDRESS);Log.e(TAG,"IP地址:"+ipAddress);if(fileTransfer==null||TextUtils.isEmpty(ipAddress)){return;}if(TextUtils.isEmpty(fileTransfer.getMd5())){Logger.e(TAG,"MD5碼為空,開(kāi)始計(jì)算文件的MD5碼");if(progressChangListener!=null){progressChangListener.onStartComputeMD5();}fileTransfer.setMd5(Md5Util.getMd5(newFile(fileTransfer.getFilePath())));Log.e(TAG,"計(jì)算結(jié)束,文件的MD5碼值是:"+fileTransfer.getMd5());}else{Logger.e(TAG,"MD5碼不為空,無(wú)需再次計(jì)算,MD5碼為:"+fileTransfer.getMd5());}intindex=0;while(ipAddress.equals("")&&index<5){Log.e(TAG,"ip:"+ipAddress);ipAddress=WifiLManager.getHotspotIpAddress(this);index++;try{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}}if(ipAddress.equals("")){return;}try{socket=newSocket();socket.bind(null);socket.connect((newInetSocketAddress(ipAddress,Constants.PORT)),20000);outputStream=socket.getOutputStream();objectOutputStream=newObjectOutputStream(outputStream);objectOutputStream.writeObject(fileTransfer);inputStream=newFileInputStream(newFile(fileTransfer.getFilePath()));startCallback();byte[]buf=newbyte[512];intlen;while((len=inputStream.read(buf))!=-1){outputStream.write(buf,0,len);total+=len;}Log.e(TAG,"文件發(fā)送成功");stopCallback();if(progressChangListener!=null){//因?yàn)樯厦嬖谟?jì)算文件傳輸進(jìn)度時(shí)因?yàn)樾?shù)點(diǎn)問(wèn)題可能不會(huì)顯示到100%,所以此處手動(dòng)將之設(shè)為100%progressChangListener.onProgressChanged(fileTransfer,0,100,0,0,0,0);progressChangListener.onTransferSucceed(fileTransfer);}}ca

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論