Android Studio设计APP实现与51单片机通过WIFI模块(ESP8266-01S)通讯控制LED灯亮灭的设计源码详解

Posted "殇影

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Studio设计APP实现与51单片机通过WIFI模块(ESP8266-01S)通讯控制LED灯亮灭的设计源码详解相关的知识,希望对你有一定的参考价值。

目录

一、前言

二、效果展示

1、APP界面展示

 2、C51硬件展示

三、Android Studio APP源代码

1、AndroidManifest.xml

1、请求联网:

2、开放明文传输:

2、MainActivity.java

3、Layout页面布局文件 activity_main.xml

四、Keil C51单片机源码

五、WIFI模块(ESP8266-01S)注意事项

六、后述     

一、前言

        本文将详细介绍如何利用android Studio设计 APP 实现与C51单片机通过WIFI模块通讯控制LED灯亮灭,本人也是新手刚入门,找了很多资料,但都不得要领,最后终于靠着摸索学习实现了手机与C51模块的WIFI通讯,特来与大家分享,希望对各位能有所帮助。废话不多说,先看效果。

二、效果展示

1、APP界面展示

 2、C51硬件展示

 

        可以看到,该APP基本实现了手机与C51单片机之间的WIFI通讯,手机端可以发送和接收数据,可以选择直接给WIFI发送数据,也可以将发送的数据的发送代码固化为按键,比如我上面的四个LED按键其实底层代码就是按下分别发送“1”、“2”、“3”、“4”来控制四个灯的亮灭。本app只是用来实验手机与C51单片机之间的WIFI通讯,目前来说算是成功了,后续可以通过修改调用该程序实现更复杂的内容,目前我也在朝着这个方向努力`(*>﹏<*)′

 

三、Android Studio APP源代码

1、AndroidManifest.xml

首先需要联网别忘了给 Android 添加网络连接权限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.tcp_led">

    
    <uses-permission android:name="android.permission.INTERNET"/> //需要对WiFi进行操作,所以需要设置网络权限

    <application
        android:usesCleartextTraffic="false"   //开放明文传输
        android:allowBackup="true"
        android:icon="@drawable/bh"
        android:label="@string/app_name"
        android:roundIcon="@drawable/bh_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.TCP_LED"
        tools:ignore="UnusedAttribute">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

1、请求联网:

 <uses-permission android:name="android.permission.INTERNET"/>

2、开放明文传输:

android:usesCleartextTraffic="false"

2、MainActivity.java

package com.example.tcp_led;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class MainActivity extends AppCompatActivity 
    String a;
    int b;
    connectthread lianjie;
    TextView receive;
    Socket socket=null;
    Button connect;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EditText ip=findViewById(R.id.mEtIP);
        EditText port=findViewById(R.id.mEtPort);
        EditText out=findViewById(R.id.mEtOut);
        receive=findViewById(R.id.receive);
        connect=findViewById(R.id.mBt1);
        Button send=findViewById(R.id.mBt7);
        Button LED1=findViewById(R.id.mBt3);
        Button LED2=findViewById(R.id.mBt4);
        Button LED3=findViewById(R.id.mBt5);
        Button LED4=findViewById(R.id.mBt6);
        Button Clear=findViewById(R.id.mBt8);

        // 连接 按键底层代码
        connect.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                a=ip.getText().toString();
                String c=port.getText().toString();
                if("".equals(a)||"".equals(c))
                    Toast.makeText(MainActivity.this,"请输入ip和端口号",Toast.LENGTH_SHORT).show();
                    receive.append("请输入ip和端口号" + "\\r\\n");
                
                elseb=Integer.parseInt(c);
                    lianjie=new connectthread();
                    lianjie.start();
            
        );

        // 发送数据 按键底层代码
        send.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                //子线程中进行网络操作
                new Thread(new Runnable() 
                    @Override
                    public void run() 
                        if(socket!=null)
                            try 
                                String text=out.getText().toString();
                                lianjie.outputStream.write(text.getBytes());
                             catch (IOException e) 
                                // TODO Auto-generated catch block
                                e.printStackTrace();

                            
                        else
                            runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                            
                                public void run()
                                
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
                                    receive.append("请先建立连接" + "\\r\\n");
                                
                            );
                        
                    
                ).start();

            
        );
        // LED1 按键底层代码 其实就是发送数据按键代码基础上修改的,后面三个按键都是
        LED1.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                //子线程中进行网络操作
                new Thread(new Runnable() 
                    @Override
                    public void run() 
                        if(socket!=null)
                            try 
                                String text="1";
                                lianjie.outputStream.write(text.getBytes());
                             catch (IOException e) 
                                // TODO Auto-generated catch block
                                e.printStackTrace();

                            
                        else
                            runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                            
                                public void run()
                                
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
                                    receive.append("请先建立连接" + "\\r\\n");
                                
                            );
                        
                    
                ).start();
            
        );
        // LED2 按键底层代码 
        LED2.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                //子线程中进行网络操作
                new Thread(new Runnable() 
                    @Override
                    public void run() 
                        if(socket!=null)
                            try 
                                String text="2";
                                lianjie.outputStream.write(text.getBytes());
                             catch (IOException e) 
                                // TODO Auto-generated catch block
                                e.printStackTrace();

                            
                        else
                            runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                            
                                public void run()
                                
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
                                    receive.append("请先建立连接" + "\\r\\n");
                                
                            );
                        
                    
                ).start();
            
        );
        // LED3 按键底层代码 
        LED3.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                //子线程中进行网络操作
                new Thread(new Runnable() 
                    @Override
                    public void run() 
                        if(socket!=null)
                            try 
                                String text="3";
                                lianjie.outputStream.write(text.getBytes());
                             catch (IOException e) 
                                // TODO Auto-generated catch block
                                e.printStackTrace();

                            
                        else
                            runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                            
                                public void run()
                                
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
                                    receive.append("请先建立连接" + "\\r\\n");
                                
                            );
                        
                    
                ).start();
            
        );
        // LED4 按键底层代码 
        LED4.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                //子线程中进行网络操作
                new Thread(new Runnable() 
                    @Override
                    public void run() 
                        if(socket!=null)
                            try 
                                String text="4";
                                lianjie.outputStream.write(text.getBytes());
                             catch (IOException e) 
                                // TODO Auto-generated catch block
                                e.printStackTrace();

                            
                        else
                            runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                            
                                public void run()
                                
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
                                    receive.append("请先建立连接" + "\\r\\n");
                                
                            );
                        
                    
                ).start();
            
        );
        Clear.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                receive.setText("");
            
        );

       // onCreate
    
    //子线程中进行网络相关操作
    // 联网子线程
    class connectthread extends Thread 

        OutputStream outputStream=null;
        InputStream inputStream=null;
        @SuppressWarnings("InfiniteLoopStatement")
        @Override
        public void run() 

            //连接
            try 
                socket=new Socket(a, b);
                runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                
                    public void run()
                    
                        // TODO Auto-generated method stub
                        Toast.makeText(MainActivity.this,"连接成功",Toast.LENGTH_SHORT).show();
                        receive.append("连接成功" + "\\r\\n");

                    
                );
             catch (UnknownHostException e) 
                // TODO Auto-generated catch block
                runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                
                    public void run()
                    
                        // TODO Auto-generated method stub
                        Toast.makeText(MainActivity.this,"连接失败",Toast.LENGTH_SHORT).show();
                        receive.append("连接失败" + "\\r\\n");
                    
                );
                e.printStackTrace();
            catch (IOException e) 
                e.printStackTrace();
                runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                
                    public void run()
                    
                        // TODO Auto-generated method stub
                        Toast.makeText(MainActivity.this,"连接失败",Toast.LENGTH_SHORT).show();
                        receive.append("连接失败" + "\\r\\n");
                    
                );
            
            if(socket!=null)
                //获取输出流对象
                try 
                    outputStream=socket.getOutputStream();
                    outputStream.write(123);
                 catch (IOException e) 
                    e.printStackTrace();
                

                try
                    do 
                        final byte[] buffer = new byte[1024];//创建接收缓冲区
                        inputStream = socket.getInputStream();
                        final int len = inputStream.read(buffer);//数据读出来,并且返回数据的长度
                        runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
                        
                            public void run() 
                                // TODO Auto-generated method stub
                                receive.append(new String(buffer, 0, len) + "\\r\\n");
                            
                        );
                     while (true);
                
                catch (IOException ignored) 

                
            
        
    
    // MainActivity

3、Layout页面布局文件 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="#f1f3f4">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TCP客户端"
            android:textSize="50dp"
            android:background="#ffffff"
            android:gravity="center"
            />
        <EditText
            android:id="@+id/mEtIP"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:inputType="textWebEditText"
            android:hint="请输入服务器IP"
            android:drawableStart="@drawable/ic_tree"
            android:drawablePadding="20dp"
            android:layout_gravity="center"
            android:textSize="20sp"
            android:autofillHints="" />
        <!--端口 -->
        <EditText
            android:id="@+id/mEtPort"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:inputType="date"
            android:hint="请输入服务器端口"
            android:drawableStart="@drawable/ic_tree"
            android:drawablePadding="20dp"
            android:layout_gravity="center"
            android:textSize="20sp"
            android:autofillHints="" />
        <!--发送 -->
        <EditText
            android:id="@+id/mEtOut"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:inputType="date"
            android:hint="请输入发送数据"
            android:drawableStart="@drawable/ic_tree"
            android:drawablePadding="20dp"
            android:layout_gravity="center"
            android:textSize="20sp"
            android:autofillHints="" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center">
            <Button
                android:id="@+id/mBt1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="连接"
                tools:ignore="UsingOnClickInXml" />
            <Button
                android:id="@+id/mBt7"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="发送数据"
                tools:ignore="UsingOnClickInXml" />
            <Button
                android:id="@+id/mBt8"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="清除"
                tools:ignore="UsingOnClickInXml" />

        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center">
            <Button
                android:id="@+id/mBt3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="LED1"
                tools:ignore="UsingOnClickInXml" />
            <Button
                android:id="@+id/mBt4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="LED2"
                tools:ignore="UsingOnClickInXml" />
            <Button
                android:id="@+id/mBt5"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="LED3"
                tools:ignore="UsingOnClickInXml" />
            <Button
                android:id="@+id/mBt6"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="LED4"
                tools:ignore="UsingOnClickInXml" />

        </LinearLayout>
        <TextView
            android:id="@+id/receive"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

布局预览:

        如此app上位机端操作就基本大功告成了,接下来就是下位机C51方面的程序了。 

四、Keil C51单片机源码

#include "reg51.h"
#define uchar unsigned char
#define uint unsigned int
	
sbit SW1=P1^0;    //S1按键
sbit LED1=P1^1;
sbit LED2=P1^2;
sbit LED3=P1^3;
sbit LED4=P1^4;

//ESP8266  EN、vcc脚接 vcc 3.3 GND 接地,必须和51共地
//ESP8266  TX 接P3^0, RX 接P3^1


bit flag=0;

uchar SendBuf[9]="LED1 ON! ";
uchar RecBuf[15];
uchar RecNum=0;

void delay_10us(uint us); //延时
void delay(uint n);   //延时
void UART_Init();   
void UART_SendByte(uchar dat);
void ESP8266_SendCmd(uchar *pbuf);
void ESP8266_SendData(uchar *pbuf); 
void ESP8266_ModeInit(void);    //WIFI模块初始化
void UART_Irq( );    // 接收信号

void delay_10us(uint us)

	while(us--);


void delay(uint n)

	uint i,j;
	for(i=0;i<n;i++)
		for(j=0;j<100;j++);


void UART_Init()

	SCON=0X50;				//串口:工作方式1
	TMOD=0X20;				//定时器:工作方式2
	TH1=0xFD;	    			//波特率:9600
	TL1=0xFD;
	ES=0;				  	//禁止串口中断
	EA=1;				 	//使能总中断
	TR1=1;					//启动计数器


void UART_SendByte(uchar dat)

	ES=0; 			    		//禁止串口中断
	SBUF=dat;       			//串口发送
	while(TI==0);   			//等待发送结束
	TI=0;           			//发送标志位清零
	ES=1; 					//使能串口中断


void ESP8266_SendCmd(uchar *pbuf)

	while(*pbuf!='\\0') 				//遇到空格跳出循环	
	
			UART_SendByte(*pbuf);
			delay_10us(5);
			pbuf++;	
	
	delay_10us(5);
	UART_SendByte('\\r');				//回车
	delay_10us(5);
	UART_SendByte('\\n');				//换行
	delay(1000);


void ESP8266_SendData(uchar *pbuf)    

	uchar i=0;
	ESP8266_SendCmd("AT+CIPSEND=0,9");  //发送数据:AT+CIPSEND=<id>,<length>
	for(i=0;i<=8;i++)
	
		UART_SendByte(*pbuf);
		delay_10us(5);
		pbuf++;	
	


void ESP8266_ModeInit(void)    //WIFI模块初始化

	
	ESP8266_SendCmd("AT+CWMODE=3");    //设置路由器模式 1:Station,,2:AP,3:Station+AP
	ESP8266_SendCmd("AT+CWSAP=\\"百行\\",\\"12345678\\",11,0");  //设置WIFI热点名称及密码
	ESP8266_SendCmd("AT+CIPAP=\\"192.168.4.2\\"");   //设置AP的IP地址
	ESP8266_SendCmd("AT+RST");                  //重新启动wifi模块
	ESP8266_SendCmd("AT+CIPMUX=1");	        //开启多连接模式
	ESP8266_SendCmd("AT+CIPSERVER=1,8080");	   //启动TCP/IP 端口为8080
	


void main()
	
   P1=0x01;
	 while(SW1);       				//等待S1键按下
   LED1=LED2=LED3=LED4=1;
	 UART_Init();      				//串口初始化
	 ESP8266_ModeInit();
	
	 ES=1;             			//允许串口中断
	
	 while(1)
	 
		 if(flag==1)
		 
			 flag = 0;
			 ESP8266_SendData(SendBuf); 
		 
		 delay(10);
	 		


void UART_Irq( ) interrupt 4   // 接收信号

	if(RI)
	
		RI=0;
		RecBuf[RecNum]=SBUF;   //接收到网络数据:+IPD,0<id>,1<数据长度>:F<接收的数据>
		if(RecBuf[0]=='+')
			RecNum++;
		else 
			RecNum=0;
		if(RecNum==10)
		
			RecNum=0;
			if(RecBuf[0]=='+'&&RecBuf[1]=='I'&&RecBuf[2]=='P'&&RecBuf[3]=='D')
			
				switch(RecBuf[9])
				
					case '1': P1 = 0xfD;break;   
					case '2': P1 = 0xfB;break;
					case '3': P1 = 0xf7;break;
					case '4': P1 = 0xef;break;
					default:P1 = 0xe0;						
				
				SendBuf[3] = RecBuf[9];
				flag = 1;
 			
						
	

五、WIFI模块(ESP8266-01S)注意事项

        相比于编写代码,硬件方面就简单多了,就是有一些需要格外注意的事项,也是我在实践中遇到的问题,现在分享给大家。

ESP8266-01S WIFI模块接线
                    TXRXD(P3^0)
                    RXTXD(P3^1)
                    EN3.3V
                    VCC3.3V
                    GNDGND

        这里需要特别注意在TX和RX中,TX代表WIFI模块发送数据,应该和单片机串行数据接收端RXD相连接,RX代表WIFI模块接受数据,应该和单片机串行数据发送端TXD相连接。EN、VCC必须接3.3V电源,另外WIFI模块工作时会发热,属于正常情况。GND接地需要特别注意,WIFI模块必须和51单片机共地,否则单片机将无法正常读取数据。其他引脚悬空就可以了,也就是说WIFI模块只需和51连接三根线即可,两根串行数据线,一根共地线。

六、后述
      

         以上就是今天要讲的内容,本文简单介绍了如何利用Android Studio设计 APP 实现与C51单片机通过WIFI模块通讯控制LED灯亮灭,由于本人也是刚开始学习,本文还有很多不足的地方,目前我的程序也还在开发中,后续我会随时更新文章中不足的部分,欢迎各位有需要的订阅我的这个专栏获取最新内容。

代码已开源:(其实以上就是全部内容了)

Github 源码资源免费下载https://github.com/SHUGEX/TCP_LED

CSDN 源码资源积分下载https://download.csdn.net/download/weixin_45694843/85238966

 

 

 

Android Studio 实现单选对话框

上效果图

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="单选对话框"
        android:textSize="20sp"
        android:layout_marginTop="30dp"
        android:gravity="center"
        android:id="@+id/tv"
        />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="设置字体大小"
        android:id="@+id/btn"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"
        />

</LinearLayout>

MainActivity.java

package com.example.singlechoicedialog;

import androidx.appcompat.app.AppCompatActivity;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener
    private AlertDialog dialog;
    private TextView textView;
    private int[] textSizeArr = 10,20,25,30,40;//存储字体大小
    private  String[] fontStyleArr= "小号","默认","中号","大号","超大";//存储样式
    int textSize = 1; //单选列表中默认选择的位置
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //设置监听
        findViewById(R.id.btn).setOnClickListener(this); //为id为btn的按钮邦定监听
        textView = (TextView) findViewById(R.id.tv);

    

    @Override
    public void onClick(View view) 
        //  创建对话框并设置其样式(这里采用链式方程)
        AlertDialog.Builder builder = new AlertDialog.Builder(this)//设置单选框列表
                .setTitle("设置字体的大小")   //设置标题
                .setIcon(R.drawable.bdd) //设置图标
                .setSingleChoiceItems(fontStyleArr, textSize, new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) 
                        textSize=i; //在OnClick方法中得到被点击的序号 i
                    
                )
                .setPositiveButton("确定", new DialogInterface.OnClickListener() //在对话框中设置“确定”按钮
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) 
                        //为TextView设置在单选对话框中选择的字体大小
                        textView.setTextSize(textSizeArr[textSize]);
                        //设置好字体大小后关闭单选对话框
                        dialog.dismiss();
                    
                )
                .setNegativeButton("取消", new DialogInterface.OnClickListener() //在对话框中设置”取消按钮“
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) 
                        dialog.dismiss();
                    
                );
        dialog = builder.create();
        dialog.show();
    

以上是关于Android Studio设计APP实现与51单片机通过WIFI模块(ESP8266-01S)通讯控制LED灯亮灭的设计源码详解的主要内容,如果未能解决你的问题,请参考以下文章

基于Android studio+SSH的单词记忆(背单词)APP设计

Android studio课程设计开发实现---日记APP

基于Android的家庭理财系统的设计与实现.rar(毕业论文设计+程序源码) android studio导入可直接打开

Android Studio 实现单选对话框

Android Studio 实现单选对话框

Android Studio 实现单选对话框