Socket 传输文件带进度(设备开热点,形成局域网)

源码地址 : https://github.com/shotter0/SocketUpdateFile.git

以前写过一片UDP 文件传输的,UDP传输效率快,有目共睹的,一般的投屏(乐播。eSHARE)都用的是UDP传输,遇到的项目。对文件完整性要求比较高,知道TCP.UDP的同学应该都知道 ,不是很清楚的去百度一下,这里我选择使用TCP 进行文件传输,

这样两台设备在局域网的情况下 ,就可以直接通讯了 ,后来经过测试。传输的速度不是很理想 ,我下载了茄子快传,那个速度正是我想要的 ,茄子快传就使用了设备开热点,另一台设备去连接那个热点,然后进行文件传输

当时我试了很久,都不知道是怎么实现的,去git上扒了一份代码 。估计很多人都知道这个XO快传,就是仿茄子快传来的。

https://github.com/mayubao/KuaiChuan

github上的项目是使用UDP进行文件传输的,我参考了,他里面的设备开启热点,设备连接,的方法 ,其实也没什么。设备开启热点之后 ,设备的IP地址是固定的,然后。。。。

直接看效果把 。

服务端(设备开热点)效果,为了方便连接,我直接使用二维码扫描进行绑定的,这样更方便用户操作

二维码里面的信息,包含了IP地址和wifi信息,用来判断手机和设备是不是同一个wifi提示用户,持续更新中,后边会添加局域网所有设备进行传输


2:手机端的界面,我使用了数据库,用来保存已经连接过的设备,便于下次直接建立连接 

     






客户端,服务端的切换处

修改 TAG_APP的值 ,直接运行,就是服务端,手机端的代码了

package com.cdl.socket.config;

import android.os.Environment;

/***
 * 常量配置类
 */
public class SocketConfig {

    public static final int TAG_SERVER = 0;
    public static final int TAG_CLIENT = 1;
    public static final int TAG_TEST = 2;

    /***
     * TAG_APP
     * 根据设备选中软件
     */
    public static int TAG_APP = TAG_SERVER;

    /***
     * 服务端,设备端通讯端口号
     */
    public static final int SERVER_PORT = 9865;

    public static final String IP_ADDRESS_HOT_WIFI = "192.168.43.1";

    /***
     * 文件接收完毕,发一个通知出来,用来刷新界面
     */
    public static final String RECEIVER_FILE_SUCCESS = "com.cdl.socket.RECEIVER_FILE_SUCCESS";

    public static final String authorities = "com.cdl.socket.fileprovider";
    /***
     * 二维码扫描返回的Code
     */
    public static final int REQUEST_CODE = SERVER_PORT + 1;

    /***
     * 文件选择器返回的返回的标志
     */
    public static final int FILE_CHOOICE_BACK = REQUEST_CODE + 1;

    /***
     * App根目录
     */
    public static final String BASE_SD_PATH = Environment.getExternalStorageDirectory().getPath() + "/mirror";

    /***
     * 存放二维码的路径
     */
    public static final String ER_CODE_PATH = BASE_SD_PATH + "/qr";

    /***
     * 用于存放接受文件的路径的
     */
    public static final String FILE_RECEIVER_PATH = BASE_SD_PATH + "/filereceive";


    /***
     * 二维码存放的路径
     */
    public static final String ERCODE_SAVE_PATH = ER_CODE_PATH + "/SocketBind.png";


}
 
 

服务端接收文件的线程 , 传输文件流,第一行传输文件名字和文件的大小,用来界面显示

package com.cdl.socket.thread;

import android.content.Intent;
import android.os.Handler;
import android.util.Log;

import com.cdl.socket.config.SocketConfig;
import com.cdl.socket.inteface.ReceiveFileListener;
import com.cdl.socket.server.ServerReceiveEntity;
import com.util.NetWorkUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerReceiveFileRunnable implements Runnable {

    private ServerSocket server;
    ReceiveFileListener listener;
    boolean isReceive = true;
    private Handler handler = new Handler();

    public ServerReceiveFileRunnable(ReceiveFileListener listener) {
        this.listener = listener;
        try {
            server = new ServerSocket(SocketConfig.SERVER_PORT);
        } catch (Exception e) {
            isReceive = false;
            backInfo(ServerReceiveEntity.RECEIVER_ERROR, "", "", 0, 0, e.toString());
        }
    }

    @Override
    public void run() {
        while (isReceive) {
            ReceiveFile();
        }
    }

    void ReceiveFile() {
        try {
            Socket name = server.accept();
            InputStream nameStream = name.getInputStream();
            InputStreamReader streamReader = new InputStreamReader(nameStream);
            BufferedReader br = new BufferedReader(streamReader);
            String nameLength = br.readLine();
            Log.e("receiveFile", "===nameLength:" + nameLength);
            String fileName = nameLength.substring(0, nameLength.indexOf(":"));
            long fileLength = Long.parseLong(nameLength.substring(nameLength.indexOf(":") + 1, nameLength.length()));
            String savePath = SocketConfig.FILE_RECEIVER_PATH + "/" + fileName;
            Log.e("receiveFile", "===接收文件的名字:" + fileName + "  //" + fileLength);
            br.close();
            streamReader.close();
            nameStream.close();
            name.close();
            backInfo(ServerReceiveEntity.RECEIVER_START, fileName, savePath, 0, fileLength, "开始接收文件");
            Socket data = server.accept();
            InputStream dataStream = data.getInputStream();
            File fileDir = new File(savePath);
            if (fileDir.exists()) {
                fileDir.delete();
            }
            fileDir.createNewFile();

            FileOutputStream file = new FileOutputStream(savePath, false);
            byte[] buffer = new byte[1024];
            int size = -1;
            long sum = 0;
            while ((size = dataStream.read(buffer)) != -1) {
                file.write(buffer, 0, size);
                sum += size;
                Log.e("====", "++++++" + NetWorkUtils.bytes2kb(sum) + "  /" + NetWorkUtils.bytes2kb(fileLength));
                backInfo(ServerReceiveEntity.RECEIVER_PROGRESS, fileName, savePath, sum, fileLength, "接收中");
            }
            file.close();
            dataStream.close();
            data.close();
            backInfo(ServerReceiveEntity.RECEIVER_SUCCESS, fileName, savePath, fileLength, fileLength, "接收成功");
        } catch (Exception e) {
            isReceive = false;
            backInfo(ServerReceiveEntity.RECEIVER_ERROR, "", "", 0, 0, e.toString());
        }
    }

    public void backInfo(final int receive_state, final String fileName, final String fileSavePath, final long fileHasReceive, final long fileTotalLength, final String receiveDesc) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                ServerReceiveEntity serverReceiveEntity = new ServerReceiveEntity(receive_state, fileName, fileSavePath, fileHasReceive, fileTotalLength, receiveDesc);
                listener.receiveFileState(serverReceiveEntity);
            }
        });
    }

    public void stopReceiveFile() {
        try {
            isReceive = false;
            if (server != null) {
                server.close();
            }
        } catch (Exception e) {
        }
    }

}

用来处理服务端消息的工具类

里面设计到权限和android 7.0的文件读取相关,详细的代码还是直接从git上面下载把 。

package com.cdl.socket.server;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.support.v4.content.FileProvider;
import android.util.Log;
import android.widget.ImageView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.cdl.socket.R;
import com.cdl.socket.activity.SocketServer;
import com.cdl.socket.config.SocketConfig;
import com.cdl.socket.inteface.ReceiveFileListener;
import com.cdl.socket.thread.ServerReceiveFileRunnable;
import com.cdl.socket.util.FileUtil;
import com.cdl.socket.util.QRCodeUtil;
import com.cdl.socket.view.GridButton;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import me.weyye.hipermission.HiPermission;
import me.weyye.hipermission.PermissionCallback;
import me.weyye.hipermission.PermissonItem;

/**
 *
 */

public class SocketReceiveUtil implements QRCodeUtil.ErCodeBackListener {

    Activity context;
    GridButton grid_button_receiver;
    ImageView iv_ercode_bind;
    ServerReceiveView serverReceiveView;
    private QRCodeUtil qrCodeUtil = null;  //二维码生成工具类

    public SocketReceiveUtil(Activity context, ServerReceiveView serverReceiveView) {
        this.context = context;
        this.serverReceiveView = serverReceiveView;
        getView();
    }

    private void getView() {
        iv_ercode_bind = serverReceiveView.getErCodeImageview();
        grid_button_receiver = serverReceiveView.getGridButton();
    }

    ServerReceiveFileRunnable receiveFileRunnable = null;

    public void receiveMessage() {
        FileUtil.creatPathNotExcit();
        receiveFileRunnable = new ServerReceiveFileRunnable(new ReceiveFileListener() {

            @Override
            public void receiveFileState(ServerReceiveEntity mServerReceiveEntity) {
                Log.e("receiveFile", "=======" + mServerReceiveEntity.toString());
                dealReceiveInfo(mServerReceiveEntity);
            }
        });
        Thread thread = new Thread(receiveFileRunnable);
        thread.start();
    }

    /***
     * 停止接收文件
     */
    public void stopReceiveFile() {
        if (receiveFileRunnable != null) {
            receiveFileRunnable.stopReceiveFile();
        }
    }

    /***
     * 处理接收的文件相关信息
     * @param mServerReceiveEntity
     */
    private void dealReceiveInfo(ServerReceiveEntity mServerReceiveEntity) {
        int state = mServerReceiveEntity.getReceive_state();
        String fileName = mServerReceiveEntity.getFileName();
        String fileSavePath = mServerReceiveEntity.getFileSavePath();
        long fileHasReceive = mServerReceiveEntity.getFileHasReceive();
        long fileTotalLength = mServerReceiveEntity.getFileTotalLength();
        String receiveDesc = mServerReceiveEntity.getReceiveDesc();
        switch (state) {
            case ServerReceiveEntity.RECEIVER_START:
                grid_button_receiver.updateProgress(fileName, 0, fileTotalLength);
                break;
            case ServerReceiveEntity.RECEIVER_PROGRESS:
                grid_button_receiver.updateProgress(fileName, fileHasReceive, fileTotalLength);
//                Intent intent = new Intent();
//                intent.setAction(SocketConfig.RECEIVER_FILE_SUCCESS);
//                context.sendBroadcast(intent);
//                try {
//                    File file = new File(fileSavePath);
//                    long fileSaveLength = file.length();
//                    grid_button_receiver.updateProgress(fileName, fileSaveLength, fileTotalLength);
//                } catch (Exception e) {
//                    serverReceiveView.showToast(e.toString());
//                }
                break;
            case ServerReceiveEntity.RECEIVER_SUCCESS:
                grid_button_receiver.resetState();
                serverReceiveView.showToast(receiveDesc);
                break;
            case ServerReceiveEntity.RECEIVER_ERROR:
                grid_button_receiver.resetState();
                serverReceiveView.showToast(receiveDesc);
                break;
        }
    }

    /***
     * 打开系统的文件管理器
     */
    public void jumpFileManager() {
        File file = new File(SocketConfig.FILE_RECEIVER_PATH);
        File parentFlie = new File(file.getParent());
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        Uri fileUrl = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {  //7.0执行该方法
            fileUrl = FileProvider.getUriForFile(context, SocketConfig.authorities, parentFlie);
        } else {  //7.0以下手机系统执行这个方法
            fileUrl = Uri.fromFile(parentFlie);
        }
        intent.setDataAndType(fileUrl, "*/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        context.startActivity(intent);
    }


    public void createErCodeImage(String ipAddress) {
        if (qrCodeUtil == null) {
            qrCodeUtil = new QRCodeUtil(context, this);
        }
        try {
            File file = new File(SocketConfig.ERCODE_SAVE_PATH);
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
            qrCodeUtil.createErCode(ipAddress, SocketConfig.ERCODE_SAVE_PATH);
        } catch (Exception e) {
            serverReceiveView.showToast(e.toString());
        }
    }

    /***
     * 检查app需要的权限
     */
    public void checkAppPermission() {
        List<PermissonItem> permissonItems = new ArrayList<PermissonItem>();
        permissonItems.add(new PermissonItem(Manifest.permission.CAMERA, "照相机", R.drawable.permission_ic_memory));
        permissonItems.add(new PermissonItem(Manifest.permission.READ_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory));
        permissonItems.add(new PermissonItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory));
        HiPermission.create(context)
                .permissions(permissonItems)
                .checkMutiPermission(new PermissionCallback() {

                    @Override
                    public void onClose() {
                    }

                    @Override
                    public void onFinish() {

                    }

                    @Override
                    public void onDeny(String permisson, int position) {
                    }

                    @Override
                    public void onGuarantee(String permisson, int position) {
                    }
                });
    }

    @Override
    public void createErCodeState(String errorDes, boolean isCreate, String filePath) {
        Log.e("ercode", "=====" + errorDes + " //" + isCreate + "  / " + filePath);
        if (isCreate) {
//            Glide.with(context).load(filePath).diskCacheStrategy(DiskCacheStrategy.NONE).into(iv_ercode_bind);
            Bitmap bitmap = BitmapFactory.decodeFile(filePath);
            iv_ercode_bind.setImageBitmap(bitmap);
        } else {
            iv_ercode_bind.setBackgroundResource(R.mipmap.ic_launcher);
            serverReceiveView.showToast(errorDes);
        }
    }
}


服务端界面显示 , 界面主要用来更新UI ,开关WIFI,和开关热点,以及一些其他的异常

package com.cdl.socket.activity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.cdl.socket.R;
import com.cdl.socket.config.SocketConfig;
import com.cdl.socket.croe.util.ApMgr;
import com.cdl.socket.croe.util.WifiMgr;
import com.cdl.socket.server.ServerReceiveView;
import com.cdl.socket.server.SocketReceiveUtil;
import com.cdl.socket.util.FileUtil;
import com.cdl.socket.util.SharedPerManager;
import com.cdl.socket.view.GridButton;
import com.cdl.view.dialog.OridinryDialog;
import com.com.view.customview.TopBarView;
import com.com.view.customview.WaitDialogUtil;
import com.util.BlueTeethUtil;
import com.view.MyToastView;

import org.json.JSONObject;

public class SocketServer extends Activity implements ServerReceiveView, View.OnClickListener {

    private TextView tv_port;
    private ImageView iv_ercode_bind;
    Button btn_junp_filepath;
    GridButton grid_button_receiver;
    SocketReceiveUtil socketReceiveUtil;
    WaitDialogUtil waitDialoUtil;
    private Handler handler = new Handler();
    TopBarView top_server;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题栏
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_server);
        FileUtil.creatPathNotExcit();
        initView();
    }

    private void initView() {
        waitDialoUtil = new WaitDialogUtil(SocketServer.this);
        grid_button_receiver = (GridButton) findViewById(R.id.grid_button_receiver);
        top_server = (TopBarView) findViewById(R.id.top_server);
        iv_ercode_bind = (ImageView) findViewById(R.id.iv_ercode_bind);
        tv_port = (TextView) findViewById(R.id.tv_port);
        tv_port.setText("端口号: " + SocketConfig.SERVER_PORT);
        btn_junp_filepath = (Button) findViewById(R.id.btn_junp_filepath);
        btn_junp_filepath.setOnClickListener(this);
        socketReceiveUtil = new SocketReceiveUtil(SocketServer.this, this);
        socketReceiveUtil.checkAppPermission();
        socketReceiveUtil.receiveMessage();
        initHotWifi();
    }

    private void initHotWifi() {
        waitDialoUtil.show("开启热点中");
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                waitDialoUtil.dismiss();
                if (ApMgr.isApOn(SocketServer.this)) {
                    MyToastView.getInstance().Toast(SocketServer.this, "创建WIFI热点成功");
                } else {
                    MyToastView.getInstance().Toast(SocketServer.this, "创建WIFI热点失败");
                }
            }
        }, 2000);
        /***
         * 0:判断wifi是否打开,打开就直接关闭
         * 1:判断AP是否打开
         * 2:没打开,就直接打开
         * 2.5:显示当前热点的名字  wifi
         * 3:设备显示 192.168.43.1  IP地址
         * 4:二维码显示 wifi + ip
         */

        boolean isWifiOpen = WifiMgr.getInstance(SocketServer.this).isWifiEnable();
        if (isWifiOpen) {
            WifiMgr.getInstance(SocketServer.this).closeWifi();
        }
        if (!ApMgr.isApOn(SocketServer.this)) {
            String bluethCode = BlueTeethUtil.getBlueToothCode();
            bluethCode = bluethCode.substring(bluethCode.length() - 4, bluethCode.length());
            boolean isCreate = ApMgr.configApState(SocketServer.this, "MirrorMagic_" + bluethCode);
            if (isCreate) {
                updateWifiView();
            }
        } else {
            updateWifiView();
        }
    }

    public void updateWifiView() {
        try {
            String hotWifiIp = SocketConfig.IP_ADDRESS_HOT_WIFI;
            top_server.setTitleText("IP : " + SocketConfig.IP_ADDRESS_HOT_WIFI);
            String bluethCode = BlueTeethUtil.getBlueToothCode();
            String wifiName = "MirrorMagic_" + (bluethCode.substring(bluethCode.length() - 4, bluethCode.length()));
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("wifi_name", wifiName);
            jsonObject.put("ip_address", hotWifiIp);
            String erCodeInfo = jsonObject.toString(1);
            socketReceiveUtil.createErCodeImage(erCodeInfo); //创建二维码
        } catch (Exception e) {
        }
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_junp_filepath:
                //  socketReceiveUtil.jumpFileManager();  //跳转到文件接收的目录
                Intent intent = new Intent(SocketServer.this, FileListActivity.class);
                intent.putExtra(FileListActivity.PATH_SEARCH, SocketConfig.FILE_RECEIVER_PATH);
                startActivity(intent);
                break;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    //======================================================================
    // @Override
    public ImageView getErCodeImageview() {
        return iv_ercode_bind;
    }

    @Override
    public GridButton getGridButton() {
        return grid_button_receiver;
    }

    @Override
    public void showToast(String toast) {
        MyToastView.getInstance().Toast(SocketServer.this, toast);
    }

    OridinryDialog oridinryDialog;

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (oridinryDialog == null) {
                oridinryDialog = new OridinryDialog(SocketServer.this, SharedPerManager.getScreenWidth(), SharedPerManager.getScreenHeight());
            }
            oridinryDialog.show("是否退出软件?", "确定", "取消");
            oridinryDialog.setOnDialogClickListener(new OridinryDialog.OridinryDialogClick() {
                @Override
                public void sure() {
                    closeAp();
                }

                @Override
                public void noSure() {

                }
            });
        }
        return super.onKeyDown(keyCode, event);
    }

    private void closeAp() {
        waitDialoUtil.show("关闭热点中");
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                waitDialoUtil.dismiss();
                boolean isWifiOpen = WifiMgr.getInstance(SocketServer.this).isWifiEnable();
                if (!isWifiOpen) {
                    WifiMgr.getInstance(SocketServer.this).openWifi();
                }

                boolean isOpen = ApMgr.isApOn(SocketServer.this);
                if (!isOpen) {  //关闭就退出
                    finish();
                } else {  //未关闭,跳转到关闭页面
                    startActivity(new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS));
                    showToast("热点关闭失败,跳转到系统设置");
                }
            }
        }, 2000);
        boolean isOpen = ApMgr.isApOn(SocketServer.this);
        if (isOpen) {
            ApMgr.disableAp(SocketServer.this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            if (socketReceiveUtil != null) {
                socketReceiveUtil.stopReceiveFile();
            }
            if (handler != null) {
                handler.removeMessages(0);
            }
        } catch (Exception e) {

        }
    }
}
 
 

手机端代码

  手机端发送文件线程,这些代码都大同小异

   

package com.cdl.socket.thread;

import android.os.Handler;
import android.util.Log;

import com.cdl.socket.config.SocketConfig;
import com.cdl.socket.inteface.MessageSendFileListener;
import com.cdl.socket.util.SharedPerManager;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;

/**
 * 发送文件线程
 * Created by cdl on 2018/2/26.
 */

public class ClienSendFileRunnable implements Runnable {

    String fileName;
    String filePath;
    String ipAddress;
    MessageSendFileListener listener;
    private Handler handler = new Handler();
    long fileTotalSize = 0;


    public ClienSendFileRunnable(String ipAddress, String fileName, String filePath, MessageSendFileListener listener) {
        this.fileName = fileName;
        this.ipAddress = ipAddress;
        this.filePath = filePath;
        this.listener = listener;
        File file = new File(filePath);
        fileTotalSize = file.length();
    }

    Socket socketDate = null;
    OutputStream outputData = null;
    FileInputStream fileInput = null;

    @Override
    public void run() {
        try {
            Socket name = new Socket(ipAddress, SocketConfig.SERVER_PORT);
            OutputStream outputName = name.getOutputStream();
            OutputStreamWriter outputWriter = new OutputStreamWriter(outputName);
            BufferedWriter bwName = new BufferedWriter(outputWriter);
            bwName.write(fileName + ":" + fileTotalSize);
            bwName.close();
            outputWriter.close();
            outputName.close();
            name.close();
            backMessageInfo(MessageSendFileListener.SEND_START, 0, 0, "开始传输");

            socketDate = new Socket(ipAddress, SocketConfig.SERVER_PORT);
            outputData = socketDate.getOutputStream();
            fileInput = new FileInputStream(filePath);

            int size = -1;
            long sum = 0;
            byte[] buffer = new byte[1024];
            while ((size = fileInput.read(buffer, 0, 1024)) != -1) {
                outputData.write(buffer, 0, size);
                sum += buffer.length;
                Log.e("write", "====" + sum);
                backMessageInfo(MessageSendFileListener.SEND_PROGRESS, (int) (sum * 100 / fileTotalSize), sum, "传输中");
            }
            outputData.close();
            fileInput.close();
            socketDate.close();
            backMessageInfo(MessageSendFileListener.SEND_SUCCESS, 100, fileTotalSize, "传输完成");
        } catch (Exception e) {
            backMessageInfo(MessageSendFileListener.SEND_ERROR, 0, 0, e.toString());
        }
    }

    private void backMessageInfo(final int sendState, final int progress, final long fileLength, final String stateDesc) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                listener.sendFileState(sendState, progress, fileLength, stateDesc);
            }
        });
    }

    /***
     * 关闭传输
     */
    public void stopSendFile() {
        try {
            if (socketDate != null) {
                socketDate.close();
            }
            if (outputData != null) {
                outputData.close();
            }
            if (fileInput != null) {
                fileInput.close();
            }
        } catch (Exception e) {
        }
    }

}

   客户端工具类,业务量不是很大 ,所以没有使用一些设计模式,框架之类的,

package com.cdl.socket.client;

import android.app.Activity;
import android.util.Log;
import android.widget.Toast;

import com.cdl.socket.activity.main.MainClientUtil;
import com.cdl.socket.db.DbManager;
import com.cdl.socket.inteface.MessageSendFileListener;
import com.cdl.socket.util.SharedPerManager;
import com.cdl.socket.view.MainView;
import com.cdl.view.dialog.FileSendDialog;
import com.cdl.view.dialog.OridinryDialog;
import com.util.NetWorkUtils;

/****
 * 客户端主界面工具类
 */
public class MainParsener implements MessageSendFileListener {
    Activity context;
    MainView mainView;
    FileSendDialog dialog;
    private OridinryDialog oridinryDialog;
    MainClientUtil mainClicntUtil;

    public MainParsener(Activity context, MainView mainView) {
        this.mainView = mainView;
        this.context = context;
        mainClicntUtil = new MainClientUtil(context, this);
        getView();
    }

    private void getView() {
        dialog = new FileSendDialog(context, SharedPerManager.getScreenWidth(), SharedPerManager.getScreenHeight());
        dialog.setOnCacleSendFileListener(new FileSendDialog.FileSendDialogListener() {

            @Override
            public void clickCacle() {  //取消发送文件
                stopSendFile();
            }
        });
    }

    /***
     * 检查Sd卡权限,并去选择图片
     */
    public void checkSdcardPermission(String ipAddress) {
        mainClicntUtil.checkSdcardPermission(ipAddress);
    }

    /***
     * 检查相机权限,并去扫描文字
     */
    public void goToScan() {
        if (!NetWorkUtils.isNetworkConnected(context)) {
            mainView.showTaost("网络未连接,请检查");
            return;
        }
        mainClicntUtil.checkCameraPermission();
    }

    /***
     * 文件发送累
     * @param ipAddress
     * @param filePath
     */
    public void sendFileMessage(String ipAddress, String filePath) {
        mainClicntUtil.sendFileMessage(ipAddress, filePath);
    }

    /***
     * 取消文件发送
     */
    public void stopSendFile() {
        mainClicntUtil.stopSendMessage();
    }

    /***
     * 检查App需要的权限
     */
    public void checkAppPermission() {
        mainClicntUtil.checkAppPermission();
    }

    public void delBindInfo(final String delInfo) {
        if (oridinryDialog == null) {
            oridinryDialog = new OridinryDialog(context, SharedPerManager.getScreenWidth(), SharedPerManager.getScreenHeight());
        }
        oridinryDialog.show("是否删除该条数据", "删除", "取消");
        oridinryDialog.setOnDialogClickListener(new OridinryDialog.OridinryDialogClick() {
            @Override
            public void sure() {
                if (DbManager.delBindInfo(delInfo)) {
                    mainView.showTaost("删除数据成功");
                    mainView.refreshDbInfo(true);
                } else {
                    mainView.refreshDbInfo(false);
                    mainView.showTaost("删除数据失败");
                }
            }

            @Override
            public void noSure() {

            }
        });
    }

    /***
     * 文件发送状态
     * @param state
     * @param progress
     * @param stateDesc
     */
    @Override
    public void sendFileState(int state, int progress, long sendLength, String stateDesc) {
        Log.e("SENDfILE", "=====" + state + " /" + progress + "  /" + stateDesc);
        switch (state) {
            case MessageSendFileListener.SEND_START:
                if (dialog != null) {
                    dialog.showDialog("准备发送文件", "取消发送");
                }
                break;
            case MessageSendFileListener.SEND_PROGRESS:
                if (dialog != null) {
                    dialog.updateSendProgress(NetWorkUtils.bytes2kb(sendLength), progress);
                }
                break;
            case MessageSendFileListener.SEND_SUCCESS:
                mainView.showTaost("传输成功");
                dialog.dissmiss();
                break;
            case MessageSendFileListener.SEND_ERROR:
                Toast.makeText(context, stateDesc, Toast.LENGTH_SHORT).show();
                dialog.dissmiss();
                break;
        }
    }
}

package com.cdl.socket.activity.main;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.cdl.socket.R;
import com.cdl.socket.config.SocketConfig;
import com.cdl.socket.inteface.MessageSendFileListener;
import com.cdl.socket.thread.ClienSendFileRunnable;
import com.uuzuche.lib_zxing.activity.CaptureActivity;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import me.weyye.hipermission.HiPermission;
import me.weyye.hipermission.PermissionCallback;
import me.weyye.hipermission.PermissonItem;

/**
 * Created by jsjm on 2018/3/3.
 */

public class MainClientUtil {

    Activity context;
    MessageSendFileListener listenerBack;

    public MainClientUtil(Activity context, MessageSendFileListener listenerBack) {
        this.listenerBack = listenerBack;
        this.context = context;
    }

    public void stopSendMessage() {
        if (clienSendFileRunnable != null) {
            clienSendFileRunnable.stopSendFile();
        }
    }


    ClienSendFileRunnable clienSendFileRunnable = null;

    public void sendFileMessage(String ipAddress, String filePath) {
        try {
            File file = new File(filePath);
            String fileName = file.getName();
            clienSendFileRunnable = new ClienSendFileRunnable(ipAddress, fileName, filePath, new MessageSendFileListener() {
                @Override
                public void sendFileState(int state, int progress, long sendFileState, String stateDesc) {
                    listenerBack.sendFileState(state, progress, sendFileState, stateDesc);
                }
            });
            Thread thread = new Thread(clienSendFileRunnable);
            thread.start();
        } catch (Exception e) {
            listenerBack.sendFileState(MessageSendFileListener.SEND_ERROR, 0, 0, e.toString());
        }
    }




    /***
     * 检查Sd卡权限,并去选择图片
     */
    public void checkSdcardPermission(String ipAddress) {
        if (TextUtils.isEmpty(ipAddress)) {
            Toast.makeText(context, "IP地址为空,请检查", Toast.LENGTH_SHORT).show();
            return;
        }
        List<PermissonItem> permissonItems = new ArrayList<PermissonItem>();
        permissonItems.add(new PermissonItem(Manifest.permission.CAMERA, "照相机", R.drawable.permission_ic_memory));
        permissonItems.add(new PermissonItem(Manifest.permission.READ_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory));
        permissonItems.add(new PermissonItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory));
        HiPermission.create(context)
                .permissions(permissonItems)
                .checkMutiPermission(new PermissionCallback() {

                    @Override
                    public void onClose() {
                    }

                    @Override
                    public void onFinish() {
                        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                        //intent.setType(“image/*”);//选择图片
                        //intent.setType(“audio/*”); //选择音频
                        //intent.setType(“video/*”); //选择视频 (mp4 3gp 是android支持的视频格式)
                        //intent.setType(“video/*;image/*”);//同时选择视频和图片
                        intent.setType("*/*");//无类型限制
                        intent.addCategory(Intent.CATEGORY_OPENABLE);
                        context.startActivityForResult(intent, SocketConfig.FILE_CHOOICE_BACK);
                    }

                    @Override
                    public void onDeny(String permisson, int position) {
                    }

                    @Override
                    public void onGuarantee(String permisson, int position) {
                    }
                });
    }


    /***
     * 检查相机权限,并去扫描文字
     */
    public void checkCameraPermission() {
        List<PermissonItem> permissonItems = new ArrayList<PermissonItem>();
        permissonItems.add(new PermissonItem(Manifest.permission.CAMERA, "照相机", R.drawable.permission_ic_memory));
        permissonItems.add(new PermissonItem(Manifest.permission.READ_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory));
        permissonItems.add(new PermissonItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory));
        HiPermission.create(context)
                .permissions(permissonItems)
                .checkMutiPermission(new PermissionCallback() {

                    @Override
                    public void onClose() {
                    }

                    @Override
                    public void onFinish() {
                        Intent intent = new Intent(context, CaptureActivity.class);
                        context.startActivityForResult(intent, SocketConfig.REQUEST_CODE);
                    }

                    @Override
                    public void onDeny(String permisson, int position) {
                    }

                    @Override
                    public void onGuarantee(String permisson, int position) {
                    }
                });
    }

    public void checkAppPermission() {
        List<PermissonItem> permissonItems = new ArrayList<PermissonItem>();
        permissonItems.add(new PermissonItem(Manifest.permission.CAMERA, "照相机", R.drawable.permission_ic_memory));
        permissonItems.add(new PermissonItem(Manifest.permission.READ_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory));
        permissonItems.add(new PermissonItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory));
        HiPermission.create(context)
                .permissions(permissonItems)
                .checkMutiPermission(new PermissionCallback() {

                    @Override
                    public void onClose() {
                    }

                    @Override
                    public void onFinish() {

                    }

                    @Override
                    public void onDeny(String permisson, int position) {
                    }

                    @Override
                    public void onGuarantee(String permisson, int position) {
                    }
                });
    }


}


手机端界面代码

package com.cdl.socket.activity;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.cdl.socket.R;
import com.cdl.socket.client.MainParsener;
import com.cdl.socket.config.SocketConfig;
import com.cdl.socket.db.BindInfo;
import com.cdl.socket.db.DbBindAdapter;
import com.cdl.socket.db.DbManager;
import com.cdl.socket.util.FileUrlUtil;
import com.cdl.socket.util.SharedPerManager;
import com.cdl.socket.view.MainView;
import com.cdl.view.dialog.OridinryDialog;
import com.com.view.customview.TopBarView;
import com.lemonade.widgets.slidesidemenu.SlideSideMenuTransitionLayout;
import com.util.NetWorkUtils;
import com.uuzuche.lib_zxing.activity.CodeUtils;

import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class SocketClient extends Activity implements MainView,
        View.OnClickListener, AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener {

    private Button btn_image_send;
    private MainParsener mainParsener;
    private TopBarView top_view_client;
    private SlideSideMenuTransitionLayout mSlideSideMenu;
    private ListView lv_da_info;
    private TextView tv_ip_local;
    DbBindAdapter adapter;
    private List<BindInfo> lists_bind = new ArrayList<>();
    FileUrlUtil fileUrlUtil;
    OridinryDialog mOridinryDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题栏
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_slide_side_menu_example);
        initView();
        initMenu();
        initListener();
    }

    private void initListener() {
        top_view_client.setTopBarListener(new TopBarView.TopBarListener() {
            @Override
            public void leftClick() {
                mSlideSideMenu.toggle();
            }

            @Override
            public void rightClick() {
                mainParsener.goToScan();  //检查相机权限并扫描二维码
            }
        });
    }

    private void initView() {
        mOridinryDialog = new OridinryDialog(SocketClient.this, SharedPerManager.getScreenWidth(), SharedPerManager.getScreenHeight());
        mSlideSideMenu = (SlideSideMenuTransitionLayout) findViewById(R.id.slide_side_menu);
        top_view_client = (TopBarView) findViewById(R.id.top_view_client);
        btn_image_send = (Button) findViewById(R.id.btn_image_send);
        btn_image_send.setOnClickListener(this);
        tv_ip_local = (TextView) findViewById(R.id.tv_ip_local);
        mainParsener = new MainParsener(SocketClient.this, this);
        mainParsener.checkAppPermission();  //检查APP需要使用的权限
        fileUrlUtil = new FileUrlUtil(SocketClient.this);
    }

    /***
     * 初始化侧滑菜单
     */
    private void initMenu() {
        lv_da_info = (ListView) findViewById(R.id.lv_da_info);
        adapter = new DbBindAdapter(SocketClient.this, lists_bind);
        lv_da_info.setAdapter(adapter);
        lists_bind = DbManager.queryBindInfo();
        adapter.setLists(lists_bind);
        lv_da_info.setOnItemClickListener(this);
        lv_da_info.setOnItemLongClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_image_send:
                mainParsener.checkSdcardPermission(getIpSend()); //检查SD卡权限 ,
                break;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        tv_ip_local.setText("本机IP: " + NetWorkUtils.GetIpAddress(SocketClient.this));
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == SocketConfig.REQUEST_CODE) {
            if (null == data) {
                return;
            }
            dealErCodeMessage(resultCode, data);
        } else if (requestCode == SocketConfig.FILE_CHOOICE_BACK) {
            Log.w("fileBack", "======接受到文件===");
            String path = "";
            //文件选择器,选择文件返回的数据
            Uri uri = data.getData();
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {//4.4以后
                path = fileUrlUtil.getPath(uri);
            } else {//4.4以下下系统调用方法
                path = fileUrlUtil.getRealPathFromURI(uri);
            }
            Log.w("fileBack", "======接受到文件===" + path);
            mainParsener.sendFileMessage(getIpSend(), path);
        }
    }

    /***
     * 处理二维码相关的业务
     * @param resultCode
     * @param data
     */
    private void dealErCodeMessage(int resultCode, Intent data) {
        try {
            Bundle bundle = data.getExtras();
            if (bundle == null) {
                showTaost("解析二维码失败");
                return;
            }
            if (bundle.getInt(CodeUtils.RESULT_TYPE) == CodeUtils.RESULT_SUCCESS) {
                String result = bundle.getString(CodeUtils.RESULT_STRING);
                JSONObject jsonject = new JSONObject(result);
                String wifi_name = jsonject.getString("wifi_name");
                String ip_address = jsonject.getString("ip_address");
                String lineWifiName = NetWorkUtils.getConnectName(SocketClient.this);
                if (!lineWifiName.contains(wifi_name.trim())) {
                    mOridinryDialog.show("请连接 <" + wifi_name + "> 这个WIFI,进行传输", "去联网", "取消");
                    mOridinryDialog.setOnDialogClickListener(new OridinryDialog.OridinryDialogClick() {

                        @Override
                        public void sure() {
                            Intent wifiSettingsIntent = new Intent("android.settings.WIFI_SETTINGS");
                            startActivity(wifiSettingsIntent);
                        }

                        @Override
                        public void noSure() {

                        }
                    });
                    return;
                }
                top_view_client.setTitleText(ip_address);
                DbManager.addBindInfo(ip_address);   //增加IP到数据库
                //扫描二维码后,刷新数据列表
                lists_bind = DbManager.queryBindInfo();
                adapter.setLists(lists_bind);
                showTaost("绑定设备成功");
            } else if (bundle.getInt(CodeUtils.RESULT_TYPE) == CodeUtils.RESULT_FAILED) {
                showTaost("解析二维码失败");
            }
        } catch (Exception e) {
            showTaost("解析二维码失败:" + e.toString());
        }
    }


    //========================================================================================
    public String getIpSend() {
        return top_view_client.getTitleText();
    }

    @Override
    public void showTaost(String desc) {
        Toast.makeText(SocketClient.this, desc, Toast.LENGTH_LONG).show();
    }

    @Override
    public void refreshDbInfo(boolean isSuccess) {
        if (isSuccess) {
            lists_bind = DbManager.queryBindInfo();
            adapter.setLists(lists_bind);
        }
    }

    /***
     * listView item点击事件
     * @param parent
     * @param view
     * @param position
     * @param id
     */
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        String bindInfoString = lists_bind.get(position).getDevicdid();
        top_view_client.setTitleText(bindInfoString);
        mSlideSideMenu.toggle();
        showTaost("绑定设备成功");
    }

    /***
     * listView 长按事件
     * @param parent
     * @param view
     * @param position
     * @param id
     * @return
     */
    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
        String delInfo = lists_bind.get(position).getDevicdid();
        mainParsener.delBindInfo(delInfo);
        return false;
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mainParsener != null) {
            mainParsener.stopSendFile();  //停止发送文件
        }
    }
}







猜你喜欢

转载自blog.csdn.net/fkgjdkblxckvbxbgb/article/details/79456563
今日推荐