话不多说,直接开干!

先来看看效果
本APP是通过tcp/ip协议与连了WiFi的单片机通信。

第一步

你得会一点点java基础,你可以去百度搜“java菜鸟教程”,学了基本的基础即可,不必太深入。

第二步

建议看一本书,是郭霖大神些的《第一行代码》,入门安卓基础。不想看书就忽略吧,我建议还是看一下最基本的例如:安卓四大组件----活动。
如果你真的一点都不想学。那就先跳过这一步。

第三步:安装Android studio软件。不会安装的小白,看过来!

注意:要安装Android studio,前提一定要安装了jdk环境。

jdk环境怎么安装?如果你电脑已经安装过eclipse并有使用过的话,就不用再安装jdk了。
打开这个链接:https://mp.weixin.qq.com/s/HKdtcd11Zk3HV3fh8_dtcw,跟着步骤做,做到15步即可。当然,如果你想要顺便把eclipse也给安装了,也无所谓。

装完jdk之后,就可以开始装Android studio了。
打开这个链接:https://www.bilibili.com/read/cv8151954
然后跟着步骤做吧。对了,下载的安装包,我建议选3.5.2 的!!!特别是小白,不然我的代码到时候你导进去各种错误可别来抱怨。

都安装完了就继续往前吧!

第四步:新建项目,开始撸代码

默认点击我标记的红色框框。请跟着我的图片操作哦。


我们给自己的项目起个名字哈:SmartHome
第二个小框框是包名,我们先不用理它是干什么的
第三个小框框是项目的存储路径
其他的不解析了





好啦我们直接开始敲代码啦!
我们先来写界面吧!

然后把我的代码复制粘贴

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity" ><LinearLayoutandroid:layout_marginTop="20dp"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><EditTextandroid:layout_marginLeft="10dp"android:layout_marginRight="5dp"android:layout_weight="1"android:id="@+id/IPText"android:layout_width="match_parent"android:layout_height="wrap_content"android:ems="10"android:textSize="20dp"android:hint="请输入衣柜服务端的IP地址" /><Buttonandroid:layout_marginRight="10dp"android:layout_weight="2"android:id="@+id/StartConnect"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="20dp"android:text="开始连接" /></LinearLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid:id="@+id/tv1"android:layout_marginLeft="20dp"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="20dp" /></RelativeLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical" ><LinearLayoutandroid:gravity="center"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:layout_marginLeft="10dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="通风"android:textSize="25sp"android:id="@+id/textView" /><Switchandroid:id="@+id/switch_c"android:layout_marginLeft="40dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textOff="OFF"android:textOn="ON"android:thumb="@drawable/thumb"android:track="@drawable/track"/></LinearLayout><LinearLayoutandroid:gravity="center"android:layout_gravity="center"android:layout_marginTop="20dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:layout_marginLeft="10dp"android:gravity="center"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="抽湿"android:textSize="25sp"android:id="@+id/textView2" /><Switchandroid:id="@+id/switch_t"android:layout_marginLeft="40dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textOff="OFF"android:textOn="ON"android:thumb="@drawable/thumb"android:track="@drawable/track"/></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:layout_marginLeft="20dp"android:layout_marginTop="15dp"android:textSize="25sp"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="温湿度:0℃"android:id="@+id/temp_text" /><TextViewandroid:layout_marginLeft="20dp"android:textSize="25sp"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="气体浓度:0%"android:id="@+id/mq_text" /></LinearLayout><TextViewandroid:id="@+id/test"android:layout_gravity="center"android:textSize="20sp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="文字显示"/><Buttonandroid:id="@+id/button_test"android:text="点击我就会变成别的文字"android:layout_width="wrap_content"android:layout_height="wrap_content"/></LinearLayout>
</RelativeLayout>


填写名字


thumb.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<!-- 设置按钮在不同状态下的时候,按钮不同的颜色 -->
<selector xmlns:android="http://schemas.android.com/apk/res/android" ><item android:state_checked="true" android:drawable="@drawable/green_thumb" /><item android:drawable="@drawable/gray_thumb" /></selector>

是不是又报错啦?如下图?

以刚才建drawable资源文件的方式,建以下5个drawable资源文件。

1.gray_thumb.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle" ><!-- 高度40 --><size android:height="40dp" android:width="40dp"/><!-- 圆角弧度 20 --><corners android:radius="20dp"/><!-- 变化率 --><gradientandroid:endColor="#ffffff"android:startColor="#ffffff" /><stroke android:width="1dp"android:color="#9e9e9e"/></shape>

2.gray_track.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle" ><!-- 高度40 --><size android:height="40dp" android:width="40dp"/><!-- 圆角弧度 20 --><corners android:radius="20dp"/><!-- 变化率 --><gradientandroid:endColor="#ffffff"android:startColor="#ffffff" /><stroke android:width="1dp"android:color="#9e9e9e"/></shape>

3.green_thumb.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle" ><!-- 高度40 --><size android:height="40dp" android:width="40dp"/><!-- 圆角弧度 20 --><corners android:radius="20dp"/><!-- 变化率 --><gradientandroid:endColor="#ffffff"android:startColor="#ffffff" /><stroke android:width="1dp"android:color="#9e9e9e"/></shape>

4.green_track.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle" ><!-- 高度40 --><size android:height="40dp" android:width="40dp"/><!-- 圆角弧度 20 --><corners android:radius="20dp"/><!-- 变化率 --><gradientandroid:endColor="#ffffff"android:startColor="#ffffff" /><stroke android:width="1dp"android:color="#9e9e9e"/></shape>

5.track.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- 控制Switch在不同状态下,底下下滑条的颜色 -->
<selector xmlns:android="http://schemas.android.com/apk/res/android" ><item android:state_checked="true" android:drawable="@drawable/green_track" /><item android:drawable="@drawable/gray_track" /></selector>







以上是比较重要的UI控件,大家了解一下,其他的一些属性我就不多说了,你们可以自己尝试修改一下参数,就会发现具体的对应的作用是什么了。

我们的ui已经做好了,现在就去写主活动类的逻辑代码!!!


我主要说说主要逻辑吧。
首先,当然是要把我们前面编写的界面都映射到我们的主活动, setContentView(R.layout.activity_main);//该activity映射的xml界面是activity_main.xml,就是这一句,然后,开启严苛模式,我们使用StrictMode,系统检测出主线程违例的情况并做出相应的反应,最终帮助开发者优化和改善代码逻辑。

接下来就是,初始化view组件 ` initView();//初始化显示的功能控件
最后对某些组件设置监听事件,以及编写对应的函数

重点来了

我们想要APP和单片机进行tcp通信,要怎么实现呢?
建立socket连接实现tcp/ip协议----这个就是我们的实现方式。

那应该怎么做
1.创建Socket(安卓作为客户端,所以是client,单片机作为server端)。
2.打开连接到Socket的输入/输出流。
3.按照协议对Socket进行读/写操作。
4.关闭输入输出流、关闭Socket。

也许说了你们可能还是不太懂,这个用代码怎么实现啊?
我先说明一下,java socket的实现和安卓平台socket的实现有一点点的区别,*在安卓里面,涉及到网络连接等耗时操作时,不能将其放在UI主线程中,需要添加子线程,在子线程进行网络连接,这就涉及到安卓线程间的通信了,用Handle来实现。这里的子线程也就是 mThreadClient。

下面直接看我的代码----MainActivity.java

package com.example.smarthome;import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
/*** 建立socket连接实现tcp/ip协议的方式:*1.创建Socket(安卓作为客户端,所以是client,单片机作为server端)**2.打开连接到Socket的输入/输出流**3.按照协议对Socket进行读/写操作**4.关闭输入输出流、关闭Socket*/
public class MainActivity extends AppCompatActivity {private Button startButton;//连接按钮private EditText IPText;//ip地址输入private boolean isConnecting=false;//判断是否连接private Thread mThreadClient=null;//子线程private Socket mSocketClient=null;//socket实现tcp、ip协议,实现tcp server和tcp client的连接private static PrintWriter mPrintWriterClient=null;//PrintWriter是java中很常见的一个类,该类可用来创建一个文件并向文本文件写入数据private  String res="";//接收的数据private  TextView warning_show, temp, mq;//警告语  温湿度  气体浓度private String []send_order={"1\n","2\n","3\n","4\n"};//发送的指令 1开启通风  2 关闭通风 3开启抽湿 4关闭抽湿@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//该activity映射的xml界面是activity_main.xmlstrictMode();//严苛模式initView();//初始化显示的功能组件}/*** 严苛模式* StrictMode类是Android 2.3 (API 9)引入的一个工具类,可以用来帮助开发者发现代码中的一些不规范的问题,* 以达到提升应用响应能力的目的。举个例子来说,如果开发者在UI线程中进行了网络操作或者文件系统的操作,* 而这些缓慢的操作会严重影响应用的响应能力,甚至出现ANR对话框。为了在开发中发现这些容易忽略的问题,* 我们使用StrictMode,系统检测出主线程违例的情况并做出相应的反应,最终帮助开发者优化和改善代码逻辑。*/private void strictMode(){StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath().build());}/*** layout组件初始化*/private void initView(){warning_show = findViewById(R.id.tv1);//警告语显示temp = findViewById(R.id.temp_text);//温湿度显示mq = findViewById(R.id.mq_text);//气体浓度显示IPText= findViewById(R.id.IPText);//ip地址和端口号IPText.setText("192.168.1.127:8080");//把ip地址和端口号设一个默认值,这个要改成你自己设置的startButton= findViewById(R.id.StartConnect);//连接按钮//连接事件  其实就是建立socket连接startButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(isConnecting){isConnecting=false;if(mSocketClient!=null){try{mSocketClient.close();mSocketClient = null;if (mPrintWriterClient!=null){mPrintWriterClient.close();mPrintWriterClient = null;}mThreadClient.interrupt();startButton.setText("开始连接");IPText.setEnabled(true);//可以输入ip和端口号warning_show.setText("断开连接\n");} catch (IOException e) {e.printStackTrace();}}}else{mThreadClient = new Thread(mRunnable);mThreadClient.start();}}});//通风开关按钮初始化final Switch switch_c=findViewById(R.id.switch_c);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {switch_c.setShowText(true);//按钮上默认显示文字}switch_c.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {if (isChecked)//当isChecked为true时,按钮就打开,并发送开的指令,当isChecked为false时,按钮就关闭,并发送关的指令{switch_c.setSwitchTextAppearance(MainActivity.this,R.style.s_true);//开关样式switch_c.setShowText(true);//显示开关为onif (send(send_order[0],-1)){showDialog("开启通风");}else{switch_c.setChecked(false);//当APP没有连接到单片机时,默认此按钮点击无效}}else{switch_c.setSwitchTextAppearance(MainActivity.this,R.style.s_false);//开关样式switch_c.setShowText(true);//显示文字onif (send(send_order[1],-1)){showDialog("关闭通风");}else{switch_c.setChecked(false);//当APP没有连接到单片机时,默认此按钮点击无效}}}});//抽湿开关按钮final Switch switch_t=findViewById(R.id.switch_t);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {switch_t.setShowText(true);//按钮上默认显示文字}switch_t.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {if (isChecked){switch_t.setSwitchTextAppearance(MainActivity.this,R.style.s_true);//开关样式switch_t.setShowText(true);//显示文字onif (send(send_order[2],-1)){showDialog("开启抽湿");}else{switch_t.setChecked(false);//当APP没有连接到单片机时,默认此按钮点击无效}}else{switch_t.setSwitchTextAppearance(MainActivity.this,R.style.s_false);//开关样式switch_t.setShowText(true);if (send(send_order[3],-1)){// flag=false;showDialog("关闭抽湿");}else{switch_t.setChecked(false);//当APP没有连接到单片机时,默认此按钮点击无效}}}});}//开启子线程private Runnable mRunnable = new Runnable() {@Overridepublic void run() {String msgText = IPText.getText().toString();if(msgText.length()<=0)//IP和端口号不能为空{Message msg = new Message();msg.what = 5;mHandler.sendMessage(msg);return;}int start = msgText.indexOf(":");//IP和端口号格式不正确if((start==-1)||(start+1>=msgText.length())){Message msg = new Message();msg.what = 6;mHandler.sendMessage(msg);return;}String sIP= msgText.substring(0,start);String sPort = msgText.substring(start+1);int port = Integer.parseInt(sPort);BufferedReader mBufferedReaderClient;//从字符输入流中读取文本并缓冲字符,以便有效地读取字符,数组和行try{//连接服务器mSocketClient = new Socket();//创建SocketSocketAddress socAddress = new InetSocketAddress(sIP, port);//设置ip地址和端口号mSocketClient.connect(socAddress, 2000);//设置超时时间为2秒//取得输入、输出流mBufferedReaderClient =new BufferedReader(new InputStreamReader(mSocketClient.getInputStream()));mPrintWriterClient=new PrintWriter(mSocketClient.getOutputStream(),true);//连接成功,把这个好消息告诉主线程,配合主线程进行更新UI。Message msg = new Message();msg.what = 1;mHandler.sendMessage(msg);}catch (Exception e) {//如果连接不成功,也要把这个消息告诉主线程,配合主线程进行更新UI。Message msg = new Message();msg.what = 2;mHandler.sendMessage(msg);return;}char[] buffer = new char[256];int count ;while(true){try{if((count = mBufferedReaderClient.read(buffer))>0)//当读取服务器发来的数据时{res = getInfoBuff(buffer,count)+"\n";//接收到的内容格式转换成字符串//当读取服务器发来的数据时,也把这个消息告诉主线程,配合主线程进行更新UI。Message msg = new Message();msg.what = 4;mHandler.sendMessage(msg);}}catch (Exception e) {// TODO: handle exception//当读取服务器发来的数据错误时,也把这个消息告诉主线程,配合主线程进行更新UI。Message msg = new Message();msg.what = 3;mHandler.sendMessage(msg);}}}};/*** 在安卓里面,涉及到网络连接等耗时操作时,不能将其放在UI主线程中,* 需要添加子线程,在子线程进行网络连接,这就涉及到安卓线程间的通信了,* 用Handle来实现。这里的子线程也就是 mThreadClient**   handle的定义: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI.*   解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) ,*   主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button,*   Android会分发事件到Button上,来响应你的操作。  如果此时需要一个耗时的操作,*   例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,*   如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,*   会收到Android系统的一个错误提示  "强制关闭".  这个时候我们需要把这些耗时的操作,*   放在一个子线程中,更新UI只能在主线程中更新,子线程中操作是危险的. 这个时候,*   Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),*   它与子线程可以通过Message对象来传递数据,这个时候,*   Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,*   里面包含数据, 把这些消息放入主线程队列中,配合主线程进行更新UI。*/@SuppressLint("HandlerLeak")Handler mHandler = new Handler(){@SuppressLint("SetTextI18n")public void handleMessage(Message msg){super.handleMessage(msg);if(msg.what==4)//当读取到服务器发来的数据时,收到了子线程的消息,而且接收到的字符串我们给它定义的是res{char []arrs;arrs=res.toCharArray();//接收来自服务器的字符串,把字符串转成字符数组if (arrs.length>=3) {if (arrs[0]=='T'){//如果字符数组的首位是T,说明接收到的信息是温湿度 T25temp.setText("温湿度:"+arrs[1]+arrs[2]+"℃");}else if (arrs[0]=='M'){//如果字符数组的首位是T,说明接收到的信息是气体浓度M66mq.setText("气体浓度:"+arrs[1]+arrs[2]+"%");}}else {showDialog("收到格式错误的数据:"+res);}}else if (msg.what==2){showDialog("连接失败,服务器走丢了");startButton.setText("开始连接");}else if (msg.what==1){showDialog("连接成功!");warning_show.setText("已连接智能衣柜\n");IPText.setEnabled(false);//锁定ip地址和端口号isConnecting = true;startButton.setText("停止连接");}else if (msg.what==3){warning_show.setText("已断开连接\n");}else if (msg.what==5){warning_show.setText("IP和端口号不能为空\n");}else if (msg.what==6){warning_show.setText("IP地址不合法\n");}}};/*** 窗口提示* @param msg*/private  void showDialog(String msg) {AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);builder.setIcon(android.R.drawable.ic_dialog_info);builder.setTitle(msg);builder.setCancelable(false);builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {}});builder.create().show();}/*** 字符数组转字符串* @param buff* @param count* @return*/private String getInfoBuff(char[] buff,int count){char[] temp = new char[count];System.arraycopy(buff, 0, temp, 0, count);return new String(temp);}/*** 发送函数* @param msg* @param position* @return*/private boolean send(String msg,int position){if(isConnecting&&mSocketClient!=null){if ((position==-1)){try{mPrintWriterClient.print(msg);mPrintWriterClient.flush();return true;}catch (Exception e) {// TODO: handle exceptionToast.makeText(MainActivity.this, "发送异常"+e.getMessage(), Toast.LENGTH_SHORT).show();}}}else{showDialog("您还没有连接衣柜呢!");}return false;}}

这个时候,我们离成功就更近一步了。包名要和自己的包名一致啊。

接下来,看图

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

一定要加上这句话哦,不然的话,就联网不成功了。

都加上了吗???
style.xml 这个忘了给,现在补上,在res的value的文件夹里,不然会有部分代码报错哦

<resources><!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"><!-- Customize your theme here. --><item name="colorPrimary">@color/colorPrimary</item><item name="colorPrimaryDark">@color/colorPrimaryDark</item><item name="colorAccent">@color/colorAccent</item>
</style>
<style name="s_true" parent="@android:style/TextAppearance.Small"><item name="android:textColor">#33da33</item>
</style><style name="s_false" parent="@android:style/TextAppearance.Small"><item name="android:textColor">#ffffff</item>
</style></resources>

我们要准备测试啦!

注意啦,如果你的电脑是运行8G以上的,就可以用模拟器运行,如果是4G的,我建议用真机测试。

4G的看过来,教你怎么快速把APP安装到手机,不用USB连接。





这个就是跳出来的文件夹


安装好了吗?我们再等等8G的朋友~

8G的朋友们还在吗?来了来了


你们一打开是这样的





然后就弄好模拟器啦


我的模拟器在开机,要等一等,等它开机完再运行。

这个是开机完的状态


要等它安装,我的安装好啦

测试了

怎么测试?直接拿单片机测试吗?
不是哦,我们可以通过网络调试助手进行测试。

需要的点网络调试助手
下载之后



然后确认你电脑的ip地址是什么?
win+R


ipv4地址就是你本机的地址。要和APP填写的一致。


测试开关按钮

测试数据接收





终于都弄好了!!!
累了累了…

后面要是自己加功能或者改功能怎么做?

我就随便讲几个例子,以后大家根据这些例子举一反三吧。

例1:如果我想增加一个文字显示,应该怎么做?


跟着我一起来动动手吧




这时候问题又来了,如果我想让它动态显示呢?就是当我点击了按钮它就换成别的文字?

这我们就得在主活动类对它进行绑定了,怎么绑定?




如果我们想要在成功连接了单片机之后,显示这个文字内容“已连接单片机”,我们就可以在对应的代码里增加代码textView.setText("已连接单片机");

然后我们运行一下APP



好啦,文字显示的就讲到这里了。

例2:如果我想增加一个按钮控件呢



它和文字显示的代码有什么区别呢?基本上是没有啥区别的,用法都差不多。

 <Buttonandroid:id="@+id/button_test"android:text="按钮"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

只不过如果是按钮要多了个监听点击事件。绑定id的方式也是TextView差不多的哦。


那么。怎么给这个按钮添加监听事件呢?

button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {button.setText("真的变了耶");}});


现在运行一下APP看看


当然,我不是要你的按钮做这件事,你可以在监听事件的代码加上任何你想做的事。

下一篇出kotlin版本的哦。
也许有小伙伴开始学的不是java版本的安卓,所以,主活动类可能代码看的会很吃力。

入门级带你实现一个安卓智能家居APP(1)java版本相关推荐

  1. 入门级带你实现一个安卓智能家居APP(2)kotlin版本

    前言 上一篇写过java版本的实现,这一篇就写一下kotlin版本的吧. 效果展示 本APP是通过tcp/ip协议与连了WiFi的单片机通信. 其实除了主活动类和新建项目时有一丢丢不同,其他的都是一样 ...

  2. 如何编写一个智能家居app

    要编写一个智能家居app,你需要考虑以下几个步骤: 确定需求:首先,你需要明确智能家居app需要满足哪些需求.这可能包括控制灯光.温度.安全系统等等. 设计架构:在确定需求后,你需要设计app的架构. ...

  3. ♥51单片机也可以实现一个小小的智能家居√(smart-home)♥

    ♥51单片机也可以实现一个小小的智能家居√(smart-home)开源所有代码♥ 文章目录 ♥51单片机也可以实现一个小小的智能家居√(smart-home)开源所有代码♥ 一.SmartHome I ...

  4. 闲谈杂记:理想中智能家居App是否都可以做成分享模式

    做了好久的App开发,主程开发的应用商店App没有20+也有15+了,下载量过百万的也大有所在,其实这些凡尔赛的数据不能归结于个人的影响力更多的是平台的影响力,但是如何让App简单易用,UI体验更友好 ...

  5. 智能家居app开发十大核心功能

    智能家居app开发概述: 智能家居可以定义为一个目标或者一个系统.利用先进的计算机.网络通信.自动控制等技术,将与家庭生活有关的各种应用子系统有机地结合在一起,通过综合管理,让家庭生活更舒适.安全 . ...

  6. android智能家居使用的协议,基于Android的智能家居APP的设计与实现论文.docx

    基于Android的智能家居APP的设计与实现中文摘要I I 基于 Android 的智能家居 APP 的设计与实现 中文摘要 本课题来源于某 IT 企业"智能家居系统"项目.移动 ...

  7. 物联网智能家居app开发,加速智能生活发展进程

    随着移动互联网的发展,人们的消费观念开始改变,物联网智能家居的概念逐渐被人们所接受,物联网智能家居app也成为了人们智慧生活的首选.智能家居app通过网络技术完成与家庭设备的连接,实现物物之间的智能交 ...

  8. android版 智能家居 kit,Android/IOS版全能家电手机APP(智能家居APP)

    主要功能说明 1.照明控制 配合KOTI各系列的遥控开关(单火或零火开关),用户可以在手机APP上实现智能灯光控制,包括灯的开关.调光控制. 2.电动窗帘控制 配合KOTI各系列的窗帘开关,用户可以在 ...

  9. 金博科技-智能家居APP开发四大分类详解

    随着物联网行业的不断开展,智能家居体系渠道及大数据服务渠道建立,下游设备厂商完善,消费者关于智能设备的承受程度将越来越大,且年纪区别将不再显着.越来越多的企业开始布局开展智能家居APP开发和应用,那么 ...

  10. 回归初心才是智能家居APP掘金市场的制胜关键

    OFweek智能家居网讯:苹果第一代iPod诞生时,乔布斯多次强调要"将1000首音乐装进口袋",但他或许没有想到,如今智能家居APP的兴起,让整个家放进口袋成为了可能.2015年 ...

最新文章

  1. 教你用深度学习LSTM网络预测流行音乐趋势(附代码)
  2. java实现 k nn算法_数据挖掘(二)——Knn算法的java实现
  3. 中科院NLPIR中文分词java版
  4. 1.我和python的第一次亲密接触
  5. 大型高并发系统的系统设计要点
  6. 中文乱码解决方案(Qt4.8.3 + Qt Creator)
  7. 在mac OSX中安装启动zookeeper
  8. pyecharts x轴字体大小调整_pyecharts 柱状图基础篇#学习笔记#
  9. 最新!全球学术排名出炉:22所中国大学位居世界100强
  10. python 内置模块random_Python3.5内置模块之random模块用法实例分析
  11. 特斯拉将国产Model 3后轮驱动版售价上调1.5万元
  12. 宝典计算机网络部分,计算机网络复习相关知识点宝典
  13. 2015年10月26日作业
  14. linux五笔教程,Linux 拼音五笔(或五笔拼音)输入法正确制作方法
  15. iOS性能优化系列篇之“优化总体原则”
  16. EDI REMADV报文详解
  17. 30个最快速的Webnbsp;Proxy代理
  18. 京东单号中转延误如何查询出的方法
  19. 飞浆AI studio人工智能课程学习(2)-Prompt优化思路|十个技巧高效优化Prompt|迭代法|Trick法|通用法|工具辅助
  20. jsoup抓取网页+详细讲解

热门文章

  1. 七牛云成功通过 CMMI3 认证
  2. 如何将图片变成png格式?怎样在线转图片格式?
  3. 疯狂脑机接口计划:马斯克的 “读心术”
  4. java 直方图_Java直方图
  5. matlab2016环境变量,matlab环境变量path
  6. 个人支付方案(免签约)-支付宝当面付
  7. 物体识别基本原理及其Python实现
  8. AndroidStudio 设置全局查找快捷键
  9. 增强现实技术AR的50个应用场景
  10. 超声波传感器(CHx01) 学习笔记 Ⅲ - I2C读写操作