Android 는 네트워크 전송 파일 이 없 는 예제 코드 를 실현 합 니 다.

최근 프로젝트 는 안 드 로 이 드 폰 간 에 네트워크 없 이 파일 을 전송 하 는 기능 을 수행 해 야 하 는데 와 이 파이 P2P(Wifi 점 대 점)라 는 기능 을 발 견 했 고 마지막 에 와 이 파 이 를 통 해 파일 을 띄 워 전송 하 는 기능 도 실 현 했 습 니 다.여기 서 저도 코드 를 정리 해서 여러분 께 공유 하 겠 습 니 다.
와 이 파이 P2P 는 안 드 로 이 드 4.0 및 더 높 은 버 전 시스템 에 추 가 된 기능 으로 와 이 파이 P2P 를 통 해 네트워크 에 연결 되 지 않 은 상태 에서 짝 짓 기 장치 와 직접 데 이 터 를 교환 할 수 있다.와 이 파이 P2P 는 블 루 투 스에 비해 검색 속도 와 전송 속도 가 빠 르 고 전송 거리 가 멀다.
실현 효 과 는 다음 과 같다.

클 라 이언 트.png

서버 쪽.png
일반적으로 개발 절 차 는 다음 과 같은 몇 가지 로 나 뉜 다.
  • AndroidManifest 에서 관련 권한(네트워크 와 파일 읽 기와 쓰기 권한)을 설명 합 니 다
  • WifiP2pManager 획득,관련 방송 감청 등록 Wifi 직 결 상태 변화
  • 특정한 장 치 를 서버(파일 을 받 을 때 사용)로 지정 하고 그룹 을 만 들 며 그룹 으로 존재 합 니 다.지정 한 포트 에서 클 라 이언 트 의 연결 요청 을 듣 고 클 라 이언 트 가 연결 요청 과 파일 전송 요청 을 기다 리 고 있 습 니 다
  • 클 라 이언 트(파일 을 보 내 는 데 사용)가 근처 의 장 치 를 주동 적 으로 검색 하고 서버 가 만 든 그룹 에 가입 하여 서버 의 IP 주 소 를 가 져 와 파일 전송 요청 을 합 니 다
  • 파일 의 완전 성 을 검증 하 다.
    성명 권한
    와 이 파이 P2P 기술 은 네트워크 에 접근 하지 않 지만 자바 소켓 에 사 용 될 수 있 기 때문에 네트워크 권한 을 신청 해 야 합 니 다.또 파일 상호 전송 을 실현 하기 위해 서 는 SD 카드 읽 기와 쓰기 권한 도 신청 해 야 한다.
    
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
      <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
      <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    등록 방송
    와 이 파이 P2P 와 관련 된 라디오 는 다음 과 같은 몇 가지 가 있 습 니 다.
  • WIFI_P2P_STATE_CHANGED_ACTION(Wifi P2P 사용 가능 여 부 를 표시 하 는 데 사용)
  • WIFI_P2P_PEERS_CHANGED_ACTION(피 어 투 피 어 노드 목록 에 변화 가 생 겼 습 니 다)
  • WIFI_P2P_CONNECTION_CHANGED_ACTION(Wifi P2P 연결 상태 가 바 뀌 었 습 니 다)
  • WIFI_P2P_THIS_DEVICE_CHANGED_ACTION(본 설비 의 설비 정보 에 변화 가 생 겼 다)
  • 이 몇 개의 방송 을 받 았 을 때,우 리 는 모두 와 이 파이 P2pManager(대등한 네트워크 관리자)에 가서 해당 하 는 정보 요청 을 해 야 하 며,채널 대상 을 요청 매개 변수 로 사용 해 야 한다.
    
    mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
    mChannel = mWifiP2pManager.initialize(this, getMainLooper(), this);
    WifiP2pManager.WIFI 를 받 았 을 때P2P_STATE_CHANGED_ACTION 방송 시 현재 와 이 파이 P2P 사용 여 부 를 판단 할 수 있 습 니 다.
    
    int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
    if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
      mDirectActionListener.wifiP2pEnabled(true);
    } else {
      mDirectActionListener.wifiP2pEnabled(false);        
    }
    
    WifiP2pManager.WIFI 를 받 았 을 때P2P_PEERS_CHANGED_ACTION 방송 시 장치 주변의 사용 가능 한 장치 목록 에 변화 가 생 겼 음 을 의미 하 며,requestPeers 방법 을 통 해 사용 가능 한 장치 목록 을 얻 은 후 그 중의 한 장 치 를 선택 하여 연결 작업 을 할 수 있 습 니 다.
    
    mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
      @Override
      public void onPeersAvailable(WifiP2pDeviceList peers) {
        mDirectActionListener.onPeersAvailable(peers.getDeviceList());
      }
    });
    
    WifiP2pManager.WIFI 를 받 았 을 때P2P_CONNECTION_CHANGED_ACTION 방송 때 와 이 파이 P2P 연결 상태 가 바 뀌 었 다 는 의미 로,어떤 장치 에 연 결 됐 거나,어떤 장치 와 연결 이 끊 겼 을 가능성 이 있다
    
    NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
    if (networkInfo.isConnected()) {
      mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() {
        @Override
        public void onConnectionInfoAvailable(WifiP2pInfo info) {
          mDirectActionListener.onConnectionInfoAvailable(info);
        }
      });
      Log.e(TAG, "   p2p  ");
    } else {
      mDirectActionListener.onDisconnection();
      Log.e(TAG, " p2p       ");
    }
    한 장치 와 연결 되 어 있 으 면 requestConnectionInfo 방법 으로 연결 정 보 를 얻 을 수 있 습 니 다.
    WifiP2pManager.WIFI 를 받 았 을 때P2P_THIS_DEVICE_CHANGED_ACTION 방송 시 본 장치 가 변 경 된 장치 정 보 를 얻 을 수 있 습 니 다.

    (WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)
    와 이 파이 P2P 의 인터페이스 가 고도 로 비동기 화 되 었 음 을 알 수 있 습 니 다.지금까지 세 시스템 의 리 셋 함수 가 사용 되 었 습 니 다.하 나 는 와 이 파이 P2pManager 의 초기 화 에 사용 되 고 두 개 는 라디오 에서 비동기 요청 데 이 터 를 사용 합 니 다.조작 을 간소화 하기 위해 사용자 정의 리 셋 함 수 를 통일 적 으로 사용 합 니 다.방법 적 의 미 는 시스템 의 리 셋 함수 와 일치 합 니 다.
    
    public interface DirectActionListener extends WifiP2pManager.ChannelListener {
      void wifiP2pEnabled(boolean enabled);
      void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo);
      void onDisconnection();
      void onSelfDeviceAvailable(WifiP2pDevice wifiP2pDevice);
      void onPeersAvailable(Collection<WifiP2pDevice> wifiP2pDeviceList);
    }
    그래서 전체 방송 수신 기 가 사용 하 는 모든 코드 는:
    
    /**
     *   :chenZY
     *   :2018/2/9 17:53
     *   :
     */
    public class DirectBroadcastReceiver extends BroadcastReceiver {
      private static final String TAG = "DirectBroadcastReceiver";
      private WifiP2pManager mWifiP2pManager;
      private WifiP2pManager.Channel mChannel;
      private DirectActionListener mDirectActionListener;
      public DirectBroadcastReceiver(WifiP2pManager wifiP2pManager, WifiP2pManager.Channel channel, DirectActionListener directActionListener) {
        mWifiP2pManager = wifiP2pManager;
        mChannel = channel;
        mDirectActionListener = directActionListener;
      }
    
      public static IntentFilter getIntentFilter() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
        return intentFilter;
      }
    
      @Override
      public void onReceive(Context context, Intent intent) {
        Log.e(TAG, "     : " + intent.getAction());
        if (!TextUtils.isEmpty(intent.getAction())) {
          switch (intent.getAction()) {
            //      Wifi P2P     
            case WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION: {
              int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
              if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                mDirectActionListener.wifiP2pEnabled(true);
              } else {
                mDirectActionListener.wifiP2pEnabled(false);
                List<WifiP2pDevice> wifiP2pDeviceList = new ArrayList<>();
                mDirectActionListener.onPeersAvailable(wifiP2pDeviceList);
              }
              break;
            }
            //            
            case WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION: {
              mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
                @Override
                public void onPeersAvailable(WifiP2pDeviceList peers) {
                  mDirectActionListener.onPeersAvailable(peers.getDeviceList());
                }
              });
              break;
            }
            // Wifi P2P           
            case WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION: {
              NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
              if (networkInfo.isConnected()) {
                mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() {
                  @Override
                  public void onConnectionInfoAvailable(WifiP2pInfo info) {
                    mDirectActionListener.onConnectionInfoAvailable(info);
                  }
                });
                Log.e(TAG, "   p2p  ");
              } else {
                mDirectActionListener.onDisconnection();
                Log.e(TAG, " p2p       ");
              }
              break;
            }
            //             
            case WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: {
              mDirectActionListener.onSelfDeviceAvailable((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
              break;
            }
          }
        }
      }
    
    }
    
    
    3.서버 쪽 에서 그룹 만 들 기
    장치 A 가 장치 B 를 검색 하고 장치 B 와 연결 되 었 다 고 가정 하면 시스템 은 자동 으로 그룹(Group)을 만 들 고 그룹 소유자(Group Owner)로 장 치 를 무 작위 로 지정 합 니 다.이때 두 대의 장치 에 있어 서 그룹의 IP 주 소 는 알 수 있 지만 클 라 이언 트 의 IP 주 소 는 다른 방법 으로 주동 적 으로 가 져 와 야 합 니 다.예 를 들 어 장치 연결 이 성공 한 후에 클 라 이언 트 가 자발적으로 서버 측 에 대한 Socket 연결 요청 을 할 수 있 습 니 다.서버 측 에서 지정 한 포트 에서 클 라 이언 트 의 연결 요청 을 감청 할 수 있 습 니 다.연결 이 성공 하면 서버 측 에서 클 라 이언 트 의 IP 주 소 를 얻 을 수 있 습 니 다.
    이 곳 에 서 는 작업 을 간소화 하기 위해 서버 엔 드(그룹 주)로 장 치 를 직접 지정 합 니 다.즉,파일 을 받 을 장 치 를 직접 지정 합 니 다.
    따라서 서버 측은 자발적으로 그룹 을 만 들 고 클 라 이언 트 의 연결 을 기 다 려 야 한다
    
    wifiP2pManager.createGroup(channel, new WifiP2pManager.ActionListener() {
      @Override
      public void onSuccess() {
        Log.e(TAG, "createGroup onSuccess");
        dismissLoadingDialog();
        showToast("onSuccess");
      }
    
       @Override
       public void onFailure(int reason) {
        Log.e(TAG, "createGroup onFailure: " + reason);
        dismissLoadingDialog();
        showToast("onFailure");
      }
    });
    
    
    여기에서 IntentService 를 사용 하여 배경 에서 클 라 이언 트 의 Socket 연결 요청 을 감청 하고 입 출력 흐름 을 통 해 파일 을 전송 합 니 다.이 곳 의 코드 는 비교적 간단 합 니 다.지정 한 포트 에서 감청 클 라 이언 트 의 연결 요청 을 계속 막 고 전송 할 파일 정보 모델 인 FileTransfer 를 가 져 온 후에 실제 데이터 전송 을 합 니 다.
    
    @Override
      protected void onHandleIntent(Intent intent) {
        clean();
        File file = null;
        try {
          serverSocket = new ServerSocket();
          serverSocket.setReuseAddress(true);
          serverSocket.bind(new InetSocketAddress(PORT));
          Socket client = serverSocket.accept();
          Log.e(TAG, "   IP   : " + client.getInetAddress().getHostAddress());
          inputStream = client.getInputStream();
          objectInputStream = new ObjectInputStream(inputStream);
          FileTransfer fileTransfer = (FileTransfer) objectInputStream.readObject();
          Log.e(TAG, "      : " + fileTransfer);
          String name = new File(fileTransfer.getFilePath()).getName();
          //          
          file = new File(Environment.getExternalStorageDirectory() + "/" + name);
          fileOutputStream = new FileOutputStream(file);
          byte buf[] = new byte[512];
          int len;
          long total = 0;
          int progress;
          while ((len = inputStream.read(buf)) != -1) {
            fileOutputStream.write(buf, 0, len);
            total += len;
            progress = (int) ((total * 100) / fileTransfer.getFileLength());
            Log.e(TAG, "      : " + progress);
            if (progressChangListener != null) {
              progressChangListener.onProgressChanged(fileTransfer, progress);
            }
          }
          serverSocket.close();
          inputStream.close();
          objectInputStream.close();
          fileOutputStream.close();
          serverSocket = null;
          inputStream = null;
          objectInputStream = null;
          fileOutputStream = null;
          Log.e(TAG, "      ,   MD5  :" + Md5Util.getMd5(file));
        } catch (Exception e) {
          Log.e(TAG, "     Exception: " + e.getMessage());
        } finally {
          clean();
          if (progressChangListener != null) {
            progressChangListener.onTransferFinished(file);
          }
          //      ,         
          startService(new Intent(this, WifiServerService.class));
        }
      }
    
    클 라 이언 트 가 여러 번 연결 요청 을 할 수 있 기 때문에 이 파일 전송 이 완료 되면(성공 하 든 실패 하 든)다시 startService 를 시작 하여 서비스 가 클 라 이언 트 의 연결 요청 을 다시 막 아야 합 니 다.
    FileTransfer 는 세 개의 필드 를 포함 하고 MD5 코드 값 은 파일 의 완전 성 을 검증 하 는 데 사 용 됩 니 다.fileLength 는 파일 의 전송 진 도 를 계산 하 는 데 사 용 됩 니 다.
    
    public class FileTransfer implements Serializable {
      //    
      private String filePath;
      //    
      private long fileLength;
      //MD5 
      private String md5;
      ・・・
    }
    파일 전송 진 도 를 외부 인터페이스 에 발표 하기 위해 서 는 Service 를 시작 해 야 하 는 것 외 에 인터페이스 가 Service 를 연결 해 야 합 니 다.파일 전송 상 태 를 업데이트 하 는 인터페이스 가 필요 합 니 다.
    
    public interface OnProgressChangListener {
        //          
        void onProgressChanged(FileTransfer fileTransfer, int progress);
        //      
        void onTransferFinished(File file);
    }
    
    
    따라서 progressChangListener 를 매개 변수 로 WifiServerService 에 전달 하고 진도 가 바 뀔 때 진도 대화 상 자 를 업데이트 해 야 합 니 다.
    
    private WifiServerService.OnProgressChangListener progressChangListener = new WifiServerService.OnProgressChangListener() {
        @Override
        public void onProgressChanged(final FileTransfer fileTransfer, final int progress) {
          runOnUiThread(new Runnable() {
            @Override
            public void run() {
              progressDialog.setMessage("   : " + new File(fileTransfer.getFilePath()).getName());
              progressDialog.setProgress(progress);
              progressDialog.show();
            }
          });
        }
    
        @Override
        public void onTransferFinished(final File file) {
          runOnUiThread(new Runnable() {
            @Override
            public void run() {
              progressDialog.cancel();
              if (file != null && file.exists()) {
                openFile(file.getPath());
              }
            }
          });
        }
      };
    
    4.클 라 이언 트 가 그룹 에 가입 하고 파일 전송 요청 을 합 니 다.
    파일 전송 인터페이스 SendFileActivity 는 DirectActionListener 인 터 페 이 스 를 실현 해 야 합 니 다.
    우선 주변 장치 정보 와 연결 상 태 를 얻 기 위해 P2P 방송 을 등록 해 야 한다.
    
    @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_send_file);
        initView();
        mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        mChannel = mWifiP2pManager.initialize(this, getMainLooper(), this);
        broadcastReceiver = new DirectBroadcastReceiver(mWifiP2pManager, mChannel, this);
        registerReceiver(broadcastReceiver, DirectBroadcastReceiver.getIntentFilter());
      }
    discoverPeers 방법 을 통 해 주변 장 치 를 검색 합 니 다.리 셋 함 수 는 방법 이 호출 되 었 는 지 여 부 를 알 리 는 데 사 용 됩 니 다.
    
    mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
      @Override
      public void onSuccess() {
        showToast("Success");
      }
    
      @Override
      public void onFailure(int reasonCode) {
        showToast("Failure");
        loadingDialog.cancel();
       }
    });
    검색 이 끝나 면 시스템 에서 WifiP2pManager.WIFI 를 터치 합 니 다.P2P_PEERS_CHANGED_ACTION 방송,이 때 requestPeers 방법 으로 장치 목록 정 보 를 얻 을 수 있 습 니 다.여 기 는 RecyclerView 로 목록 을 보 여 줍 니 다.onPeersAvailable 방법 으로 목록 을 새로 고 칠 수 있 습 니 다.
    
    mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
      @Override
      public void onPeersAvailable(WifiP2pDeviceList peers) {
        mDirectActionListener.onPeersAvailable(peers.getDeviceList());
      }
    });
    
    
    @Override
      public void onPeersAvailable(Collection<WifiP2pDevice> wifiP2pDeviceList) {
        Log.e(TAG, "onPeersAvailable :" + wifiP2pDeviceList.size());
        this.wifiP2pDeviceList.clear();
        this.wifiP2pDeviceList.addAll(wifiP2pDeviceList);
        deviceAdapter.notifyDataSetChanged();
        loadingDialog.cancel();
      }
    이후 이벤트 클릭 을 통 해 그룹 주(서버 쪽)장 치 를 선택 하고 connect 방법 으로 연결 을 요청 합 니 다.
    
    private void connect() {
      WifiP2pConfig config = new WifiP2pConfig();
      if (config.deviceAddress != null && mWifiP2pDevice != null) {
        config.deviceAddress = mWifiP2pDevice.deviceAddress;
        config.wps.setup = WpsInfo.PBC;
        showLoadingDialog("     " + mWifiP2pDevice.deviceName);
        mWifiP2pManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {
          @Override
          public void onSuccess() {
            Log.e(TAG, "connect onSuccess");
          }
    
          @Override
          public void onFailure(int reason) {
            showToast("     " + reason);
            dismissLoadingDialog();
          }
        });
      }
    }
    함수 함수 로 연결 결 과 를 판단 할 수 없습니다.시스템 에서 보 내 는 WifiP2pManager.WIFIP2P_CONNECTION_CHANGED_ACTION 방법 으로 연결 결 과 를 얻 을 수 있 습 니 다.여기 서 requestConnectionInfo 를 통 해 그룹 연결 정 보 를 얻 을 수 있 습 니 다.정 보 는 마지막 으로 onConnectionInfoAvailable 방법 으로 전 달 됩 니 다.여기 서 현재 장치 가 그룹 주인 인지,그룹 IP 주 소 를 얻 을 수 있 습 니 다.
    
    @Override
    public void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo) {
      dismissLoadingDialog();
      wifiP2pDeviceList.clear();
      deviceAdapter.notifyDataSetChanged();
      btn_disconnect.setEnabled(true);
      btn_chooseFile.setEnabled(true);
      Log.e(TAG, "onConnectionInfoAvailable");
      Log.e(TAG, "onConnectionInfoAvailable groupFormed: " + wifiP2pInfo.groupFormed);
      Log.e(TAG, "onConnectionInfoAvailable isGroupOwner: " + wifiP2pInfo.isGroupOwner);
      Log.e(TAG, "onConnectionInfoAvailable getHostAddress: " + wifiP2pInfo.groupOwnerAddress.getHostAddress());
      StringBuilder stringBuilder = new StringBuilder();
      if (mWifiP2pDevice != null) {
        stringBuilder.append("      :");
        stringBuilder.append(mWifiP2pDevice.deviceName);
        stringBuilder.append("
    "); stringBuilder.append(" :"); stringBuilder.append(mWifiP2pDevice.deviceAddress); } stringBuilder.append("
    "); stringBuilder.append(" :"); stringBuilder.append(wifiP2pInfo.isGroupOwner ? " " : " "); stringBuilder.append("
    "); stringBuilder.append(" IP :"); stringBuilder.append(wifiP2pInfo.groupOwnerAddress.getHostAddress()); tv_status.setText(stringBuilder); if (wifiP2pInfo.groupFormed && !wifiP2pInfo.isGroupOwner) { this.wifiP2pInfo = wifiP2pInfo; } }
    이로써 서버 측 과 클 라 이언 트 는 와 이 파이 P2P 를 통 해 연결 되 었 고 클 라 이언 트 도 서버 측의 IP 주 소 를 가 져 왔 습 니 다.보 낼 파일 을 선택 한 후에 서버 측 에 대한 연결 요청 을 주동 적 으로 할 수 있 습 니 다.
    파일 선택 방법 시작
    
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("*/*");
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    startActivityForResult(intent, 1);
    
    선택 한 파일 의 실제 경로 가 져 오기
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
      if (requestCode == 1) {
        if (resultCode == RESULT_OK) {
          Uri uri = data.getData();
          if (uri != null) {
            String path = getPath(this, uri);
            if (path != null) {
              File file = new File(path);
              if (file.exists() && wifiP2pInfo != null) {
                FileTransfer fileTransfer = new FileTransfer(file.getPath(), file.length());
                Log.e(TAG, "      :" + fileTransfer);
                new WifiClientTask(this, fileTransfer).execute(wifiP2pInfo.groupOwnerAddress.getHostAddress());
              }
            }
          }
        }
      }
    }
    
    private String getPath(Context context, Uri uri) {
      if ("content".equalsIgnoreCase(uri.getScheme())) {
        Cursor cursor = context.getContentResolver().query(uri, new String[]{"_data"}, null, null, null);
        if (cursor != null) {
          if (cursor.moveToFirst()) {
            String data = cursor.getString(cursor.getColumnIndex("_data"));
            cursor.close();
            return data;
          }
        }
      } else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
      }
      return null;
    }
    파일 전송 작업 을 AsyncTask 에서 처리 하고 서버 쪽 의 IP 주 소 를 매개 변수 로 전송 합 니 다.정식 파일 을 보 내기 전에 파일 정보(파일 이름,파일 크기,파일 MD5 코드)를 포함 하 는 정보 모델 FileTransfer 를 보 내 고 파일 을 보 내 는 과정 에서 진 도 를 동시에 업데이트 합 니 다.
    
    /**
     *   :    
     *   :2018/2/15 8:51
     *   :       
     */
    public class WifiClientTask extends AsyncTask<String, Integer, Boolean> {
      private ProgressDialog progressDialog;
      private FileTransfer fileTransfer;
      private static final int PORT = 4786;
      private static final String TAG = "WifiClientTask";
      public WifiClientTask(Context context, FileTransfer fileTransfer) {
        this.fileTransfer = fileTransfer;
        progressDialog = new ProgressDialog(context);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setCancelable(false);
        progressDialog.setCanceledOnTouchOutside(false);
        progressDialog.setTitle("      ");
        progressDialog.setMax(100);
      }
    
      @Override
      protected void onPreExecute() {
        progressDialog.show();
      }
    
      @Override
      protected Boolean doInBackground(String... strings) {
        fileTransfer.setMd5(Md5Util.getMd5(new File(fileTransfer.getFilePath())));
        Log.e(TAG, "   MD5   :" + fileTransfer.getMd5());
        Socket socket = null;
        OutputStream outputStream = null;
        ObjectOutputStream objectOutputStream = null;
        InputStream inputStream = null;
        try {
          socket = new Socket();
          socket.bind(null);
          socket.connect((new InetSocketAddress(strings[0], PORT)), 10000);
          outputStream = socket.getOutputStream();
          objectOutputStream = new ObjectOutputStream(outputStream);
          objectOutputStream.writeObject(fileTransfer);
          inputStream = new FileInputStream(new File(fileTransfer.getFilePath()));
          long fileSize = fileTransfer.getFileLength();
          long total = 0;
          byte buf[] = new byte[512];
          int len;
          while ((len = inputStream.read(buf)) != -1) {
            outputStream.write(buf, 0, len);
            total += len;
            int progress = (int) ((total * 100) / fileSize);
            publishProgress(progress);
            Log.e(TAG, "      :" + progress);
          }
          outputStream.close();
          objectOutputStream.close();
          inputStream.close();
          socket.close();
          outputStream = null;
          objectOutputStream = null;
          inputStream = null;
          socket = null;
          Log.e(TAG, "      ");
          return true;
        } catch (Exception e) {
          Log.e(TAG, "       Exception: " + e.getMessage());
        } finally {
          if (outputStream != null) {
            try {
              outputStream.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
          if (objectOutputStream != null) {
            try {
              objectOutputStream.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
          if (inputStream != null) {
            try {
              inputStream.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
          if (socket != null) {
            try {
              socket.close();
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        }
        return false;
      }
    
      @Override
      protected void onProgressUpdate(Integer... values) {
        progressDialog.setProgress(values[0]);
      }
    
      @Override
      protected void onPostExecute(Boolean aBoolean) {
        progressDialog.cancel();
        Log.e(TAG, "onPostExecute: " + aBoolean);
      }
    
    }
    
    5.파일 의 완전 성 검사
    전송 파일 의 완전 성 은 주로 파일 의 MD5 코드 값 을 계산 하여 보장 합 니 다.파일 을 보 내기 전에 WifiClient Task 의 doInBackground 방법 에서 계산 하고 MD5 코드 값 을 FileTransfer 모델 에 부여 합 니 다.다음 과 같은 방법 으로 계산 할 수 있 습 니 다.
    
    /**
     *   :    
     *   :2018/2/14 21:16
     *   :
     */
    public class Md5Util {
      public static String getMd5(File file) {
        InputStream inputStream = null;
        byte[] buffer = new byte[2048];
        int numRead;
        MessageDigest md5;
        try {
          inputStream = new FileInputStream(file);
          md5 = MessageDigest.getInstance("MD5");
          while ((numRead = inputStream.read(buffer)) > 0) {
            md5.update(buffer, 0, numRead);
          }
          inputStream.close();
          inputStream = null;
          return md5ToString(md5.digest());
        } catch (Exception e) {
          return null;
        } finally {
          if (inputStream != null) {
            try {
              inputStream.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        }
      }
    
      private static String md5ToString(byte[] md5Bytes) {
        StringBuilder hexValue = new StringBuilder();
        for (byte b : md5Bytes) {
          int val = ((int) b) & 0xff;
          if (val < 16) {
            hexValue.append("0");
          }
          hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
      }
    }
    클 라 이언 트 가 FileTransfer 를 서버 에 전송 하기 때문에 서버 측은 파일 전송 이 끝 난 후에 파일 의 MD5 코드 값 을 다시 계산 하여 파일 의 완전 여 부 를 판단 할 수 있 습 니 다.
    여기 서 상기 코드 를 공유 합 니 다Android 에서 네트워크 없 는 전송 파일 구현 
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기