通过蓝牙实现手机与手机聊天,手机与单片机通讯(二. 代码篇之发送接收数据)

前面两篇讲的是布局,连接设备,这一节我们来说一说如何通过蓝牙来发送接收数据吧、

大概步骤就是,我们先定义两个线程,分别是客户端的接收线程,还有服务端接收线程,这两个线程我们主要来接收数据,那个发送数据,我们定义了一个send()方法,分别在oncread(),onItemClick()两个方法中调用(第一个是用给服务端发送数据,第二个是用来给客户端发送数据)。

首先,我们涉及到聊天界面,肯定要用到消息处理,类似微信的聊天界面,我们在程序中就得自定义一下聊天界面。

①:新建消息类Msg,功能是将发送的消息显示在右边,接收的消息放在左边。

public class Msg {
    public static final int TYPE_RECEIVED = 0;
    public static final int TYPE_SENT = 1;
    private String content;
    private int type;
    public Msg(String content, int type){
        this.content = content;
        this.type = type;
    }
    public String getContent(){
        return content;
    }
    public int getType(){
        return type;
    }

}

②:新建MyAdapter适配器

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.List;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
    private List<Msg> mMsgList;
    static class ViewHolder extends RecyclerView.ViewHolder{
        LinearLayout leftLayout;
        LinearLayout rightLayout;
        TextView leftMsg;
        TextView rightMsg;
        public ViewHolder(View view){
            super(view);
            leftLayout = (LinearLayout) view.findViewById(R.id.left_layout);
            rightLayout = (LinearLayout) view.findViewById(R.id.right_layout);
            leftMsg = view.findViewById(R.id.left_msg);
            rightMsg = view.findViewById(R.id.right_msg);
        }
    }
    public MyAdapter(List<Msg> msgList){
        this.mMsgList = msgList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);
        ViewHolder holder =  new ViewHolder(view);
        return  holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Msg msg = mMsgList.get(position);
        if(msg.getType()==Msg.TYPE_RECEIVED){
            //如果收到消息,则在左边显示,右边隐藏
            holder.leftLayout.setVisibility(View.VISIBLE);
            holder.rightLayout.setVisibility(View.GONE);
            holder.leftMsg.setText(msg.getContent());
        }else if(msg.getType() == Msg.TYPE_SENT){
            holder.rightLayout.setVisibility(View.VISIBLE);
            holder.leftLayout.setVisibility(View.GONE);
            holder.rightMsg.setText(msg.getContent());
        }
    }
    @Override
    public int getItemCount() {
        return mMsgList.size();
    }
}

③:回到我们的MainActivity,先定义线程,分别有服务端和客户端的,用来时刻接收数据。

private RecyclerView msgRecyclerView;
private List<Msg> msgList  = new ArrayList<>();
private IntentFilter filter;
private OutputStream os;
private InputStream in;
private SeverAcceptThread thread;
private AcceptThread Thread1;
private String content1;
/**************************************客户端IO线程**********************************************/
    private class AcceptThread extends Thread{
        public void run() {
            try {
                    os = bluetoothSocket.getOutputStream();
                    in = bluetoothSocket.getInputStream();
                while (true) {
                    // 创建一个128字节的缓冲
                    byte[] buffer = new byte[128];
                    // 每次读取128字节,并保存其读取的角标
                    int count = in.read(buffer);
                    // 创建Message类,向handler发送数据
                    Message msg = new Message();
                    // 发送一个String的数据,让他向上转型为obj类型
                    msg.obj = new String(buffer, 0, count);
                    // 发送数据
                    handler.sendMessage(msg);
                }
            } catch (IOException e) {
                Log.d("CZK","线程有问题");
            }


        }
    }
/*************************************服务端IO线程**********************************/
private class SeverAcceptThread extends Thread{
    private BluetoothServerSocket serverSocket;// 获取服务端接口
    private BluetoothSocket socket;// 获取到客户端的接口
    private InputStream is;// 获取到输入流
    private SeverAcceptThread(){
        try {
            // 通过UUID监听请求,然后获取到对应的服务端接口
            serverSocket = bluetoothAdapter
                    .listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
    public void run(){
        try {
            Log.d("CZK","thread start");
            // 接收其客户端的接口
            socket = serverSocket.accept();
            // 获取到输入流
            is = socket.getInputStream();
            // 获取到输出流
            os = socket.getOutputStream();
            // 无线循环来接收数据
            while (true) {
                // 创建一个128字节的缓冲
                byte[] buffer = new byte[128];
                // 每次读取128字节,并保存其读取的角标
                int count = is.read(buffer);
                // 创建Message类,向handler发送数据
                Message msg = new Message();
                // 发送一个String的数据,让他向上转型为obj类型
                msg.obj = new String(buffer, 0, count);
                // 发送数据
                handler.sendMessage(msg);
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }




    }
}

④:定义send()方法,主要来发送数据

/*****************************************send*****************************************/
private void send(){
    msgRecyclerView = findViewById(R.id.recycler_view);
    editText = findViewById(R.id.input_text);
    send = findViewById(R.id.send1);
    LinearLayoutManager LayoutManager = new LinearLayoutManager(this);
    msgRecyclerView.setLayoutManager(LayoutManager);
    Myadapter = new MyAdapter(msgList);
    msgRecyclerView.setAdapter(Myadapter);
    send.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.d("CZK","click");
            content1 = editText.getText().toString();
            if(!"".equals(content1)) {
                Msg msg1 = new Msg(content1, Msg.TYPE_SENT);
                msgList.add(msg1);
                Myadapter.notifyItemInserted(msgList.size()); //刷新
                msgRecyclerView.scrollToPosition(msgList.size() - 1);       //定位
                try {
                    os.write(content1.getBytes());
                    Log.d("CZK","向客户端发送消息成功");
                } catch (IOException e) {
                    e.printStackTrace();
                }
                editText.setText("");
            }
        }
    });
}

⑤:在之前的OnitemClick()中添加客户端线程并加入send()方法。

//启动线程
// 实例接收客户端传过来的数据线程
Thread1 = new AcceptThread();
// 线程开始
Thread1.start();
setContentView(R.layout.activity_main);
setTitle("与"+ bluetoothDevice.getName()+"连接中");
send();

⑥:重定义Handle类,用来处理接收的数据。

/****************************************Handler****************************/
@SuppressLint("HandlerLeak")
Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        Msg msg2 = new Msg(msg.obj.toString(),Msg.TYPE_RECEIVED);
        msgList.add(msg2);
        Myadapter.notifyItemInserted(msgList.size()); //刷新
        msgRecyclerView.scrollToPosition(msgList.size()-1);       //定位
    }
};

⑦:onCreat()

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setTitle("蓝牙助手");
    bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    // 用Set集合保持已绑定的设备
    Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();
    if (devices.size() > 0) {
        for (BluetoothDevice bluetoothDevice : devices) {
            // 保存到arrayList集合中
            list.add(bluetoothDevice.getName() + ":"
                    + bluetoothDevice.getAddress() + "\n");
            adapter = new ArrayAdapter<>(MainActivity.this,android.R.layout.simple_list_item_1,android.R.id.text1,list);
            listView.setAdapter(adapter);
            adapter.notifyDataSetChanged();

        }
    }
    send();
    thread = new SeverAcceptThread();
    // 线程开始
    thread.start();

}

猜你喜欢

转载自blog.csdn.net/qq_42246939/article/details/81358440