通過Android Studio建立SocketTCP客戶端發送字符串
上回書說到,STM32通過Socket建立TCP服務器之後可以通過TCP客戶端來給它發出指令,但是電腦發指令就比較麻煩,所以花了兩天時間學習力Android Studio來建立一個TCP客戶端與單片機通信,今天的主要內容是Android是怎麼通過線程發送一個字符串,以及Android的UI怎麼建立
Android UI建立
在Android Studio中就有現成的一些工具,可以直接拖出使用,2天學會主要是UI這麼搞就沒有花費時間。
首先建立一個Android的工程,選取空白模板,在該工程的res文件夾下的layout文件內的文件就是我們的項目UI,下面附上我的UI
接下來是UI對應代碼,僅供參考:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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=".TCPClient">
<Button
android:id="@+id/Button"
style="@android:style/Widget.Material.Light.Button.Small"
android:layout_width="175dp"
android:layout_height="49dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:onClick="link"
android:text="連 接 服 務 器"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.083"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.669"
tools:ignore="NewApi,RtlCompat" />
<TextView
android:layout_width="145dp"
android:layout_height="51dp"
android:layout_marginLeft="16dp"
android:fontFamily="sans-serif"
android:text="TcpClient"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.051"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.029" />
<TextView
android:id="@+id/textView3"
android:layout_width="96dp"
android:layout_height="37dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="發送數據"
android:textAlignment="center"
android:textSize="22sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.01"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.218" />
<EditText
android:id="@+id/dataEdit"
android:layout_width="245dp"
android:layout_height="43dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:ems="10"
android:inputType="textPersonName"
android:text=" LED0ON"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.211" />
<Button
android:id="@+id/button"
style="@android:style/Widget.Material.Light.Button.Small"
android:layout_width="175dp"
android:layout_height="49dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:onClick="play1"
android:text="1號啓動"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.083"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.346"
tools:ignore="NewApi" />
<EditText
android:id="@+id/editText"
android:layout_width="354dp"
android:layout_height="177dp"
android:layout_marginTop="24dp"
android:ems="10"
android:inputType="textMultiLine"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.513"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.977" />
<Button
android:id="@+id/button2"
style="@android:style/Widget.Material.Light.Button.Small"
android:layout_width="175dp"
android:layout_height="49dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:onClick="play2"
android:text="2號啓動"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.932"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.345"
tools:ignore="NewApi" />
<Button
android:id="@+id/button3"
style="@android:style/Widget.Material.Light.Button.Small"
android:layout_width="175dp"
android:layout_height="49dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:onClick="play3"
android:text="3號啓動"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.08"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.473"
tools:ignore="NewApi" />
<Button
android:id="@+id/button4"
style="@android:style/Widget.Material.Light.Button.Small"
android:layout_width="175dp"
android:layout_height="49dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:onClick="play4"
android:text="4號啓動"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.932"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.473"
tools:ignore="NewApi" />
</android.support.constraint.ConstraintLayout>
以上代碼寫完,UI結束,效果爲上圖
Android Activity建立TCP客戶端
話不多說,直接上代碼,由於修改原因有一些代碼是無效的,但是不影響App的使用,代碼具體功能我會在代碼內部解釋
package com.example.a96913.myapplication;
import android.content.DialogInterface; //需要的庫,Android Studio會幫忙定義的
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class MaintcpclientActivity extends AppCompatActivity //主動作
{
String datatoedit; // 用於Socket的發送buff
String data10=" LED1OFF";
String data20=" LED2OFF";
String data30=" LED3OFF";
String data40=" LED4OFF";
String data11=" LED1ON";
String data21=" LED2ON";
String data31=" LED3ON";
String data41=" LED4ON"; //以上爲驅動我的STM32需要的信息,未加密,大佬別噴
Button Button;//連接服務器按鈕對象
Button Button1;//1號接口按鈕對象
Button Button2;//2號接口按鈕對象
Button Button3;//3號接口按鈕對象
Button Button4;//4號接口按鈕對象
EditText edittotext;//接收的數據顯示編輯框對象
Socket Socket = null;//Socket
boolean buttontitle = true;//定義一個邏輯變量,用於判斷連接服務器按鈕狀態
boolean b1 = true;//定義一個邏輯變量,用於判斷1號接口按鈕狀態
boolean b2 = true;//定義一個邏輯變量,用於判斷2號接口按鈕狀態
boolean b3 = true;//定義一個邏輯變量,用於判斷3號接口按鈕狀態
boolean b4 = true;//定義一個邏輯變量,用於判斷4號接口按鈕狀態
boolean RD = false;//用於控制讀數據線程是否執行
OutputStream OutputStream = null; //定義數據輸出流,用於發送數據
InputStream InputStream = null; //定義數據輸入流,用於接收數據
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maintcpclient);
Button = (Button)findViewById(R.id.Button); //獲取連接服務器按鈕對象
Button1 = (Button)findViewById(R.id.button); //獲取1號接口按鈕對象
Button2 = (Button)findViewById(R.id.button2);//獲取2號接口按鈕對象
Button3 = (Button)findViewById(R.id.button3);//獲取3號接口按鈕對象
Button4 = (Button)findViewById(R.id.button4);//獲取4號接口按鈕對象
edittotext = (EditText)findViewById(R.id.editText);//獲取接收數據顯示編輯框對象
}
//1號按鈕按下
public void play1(View view)
{
//驗證編輯框用戶輸入內容是否合法
if (b1 == true)
{
//如果按鈕沒有被按下,則按鈕狀態改爲按下
b1 = false;
//啓動一個新的線程,用於發送數據
datatoedit = data11;
ThreadSendData t1 = new ThreadSendData();
t1.start();
//改變按鈕標題
Button1.setText("1號運行中");
}
else
{
Button1.setText("1號啓動"); //如果按鈕已經被按下,則改變按鈕標題
b1 = true; //儲存狀態的變量反轉
datatoedit = data10;
ThreadSendData t1 = new ThreadSendData(); //啓動一個新的線程,用於發送數據
t1.start();
}
}
//2號按鈕按下
public void play2(View view)
{
if (b2 == true)
{
b2 = false;
datatoedit = data21; //如果按鈕沒有被按下,則按鈕狀態改爲按下
ThreadSendData t2 = new ThreadSendData(); //啓動一個新的線程,用於發送數據
t2.start();
Button2.setText("2號運行中"); //改變按鈕標題
}
else
{
Button2.setText("2號啓動"); //如果按鈕已經被按下,則改變按鈕標題
b2 = true; //儲存狀態的變量反轉
datatoedit = data20;
ThreadSendData t2 = new ThreadSendData(); //啓動一個新的線程,用於發送數據
t2.start();
}
}
//3號按鈕按下
public void play3(View view)
{
if (b3 == true)
{
b3 = false; //如果按鈕沒有被按下,則按鈕狀態改爲按下
datatoedit = data31;
ThreadSendData t3 = new ThreadSendData(); //啓動一個新的線程,用於發送數據
t3.start();
Button3.setText("3號運行中"); //改變按鈕標題
}
else
{
Button3.setText("3號啓動"); //如果按鈕已經被按下,則改變按鈕標題
b3 = true; //儲存狀態的變量反轉
datatoedit = data30;
ThreadSendData t3 = new ThreadSendData(); //啓動一個新的線程,用於發送數據
t3.start();
}
}
//4號按鈕按下
public void play4(View view)
{
if (b4 == true)
{
b4 = false; //如果按鈕沒有被按下,則按鈕狀態改爲按下
datatoedit = data41;
ThreadSendData t4 = new ThreadSendData(); //啓動一個新的線程,用於發送數據
t4.start();
Button4.setText("4號運行中"); //改變按鈕標題
}
else
{
Button4.setText("4號啓動"); //如果按鈕已經被按下,則改變按鈕標題
b4 = true; //儲存狀態的變量反轉
datatoedit = data40;
ThreadSendData t4 = new ThreadSendData(); //啓動一個新的線程,用於發送數據
t4.start();
}
}
//連接服務器按鈕按下
public void link(View view)
{
if (buttontitle == true) //判斷按鈕狀態
{
buttontitle = false; //如果按鈕沒有被按下,則按鈕狀態改爲按下
RD = true; //讀數據線程可以執行
Connect_Thread Connect_thread = new Connect_Thread(); //並創建一個新的線程,用於初始化socket
Connect_thread.start();
Button.setText("斷 開 連 接"); //改變按鈕標題
}
else
{
Button.setText("連 接 服 務 器"); //如果按鈕已經被按下,則改變按鈕標題
buttontitle = true; //儲存狀態的變量反轉
try
{
Socket.close(); //取消socket
Socket = null; //socket設置爲空
RD = false; //讀數據線程不執行
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
class Connect_Thread extends Thread //用線程創建Socket連接
{
public void run()
{
try {
if (Socket == null) //判斷socket的狀態,防止重複執行
{
Socket = new Socket("172.16.108.64",50000); //如果socket爲空則執行新建一個socket
InputStream = Socket.getInputStream();//獲取socket的輸入流和輸出流
OutputStream = Socket.getOutputStream();
ThreadReadData t1 = new ThreadReadData();//新建一個線程讀數據
t1.start();
}
}
catch (Exception e) //如果有錯誤則在這裏返回
{
e.printStackTrace();
}
}
}
class ThreadReadData extends Thread //用線程執行讀取服務器發來的數據
{
public void run()
{
String textdata; //定義一個變量用於儲存服務器發來的數據
while (RD) //根據RD變量的值判斷是否執行讀數據
{
try
{
final byte[] ReadBuffer = new byte[2048]; //定義一個字節集,存放輸入的數據,緩存區大小爲2048字節
final int ReadBufferLengh; //用於存放數據量
//從輸入流獲取服務器發來的數據和數據寬度
//ReadBuffer爲參考變量,在這裏會改變爲數據
//輸入流的返回值是服務器發來的數據寬度
ReadBufferLengh = InputStream.read(ReadBuffer);
if (ReadBufferLengh == -1) //驗證數據寬度,如果爲-1則已經斷開了連接
{
RD = false;//重新歸位到初始狀態
Socket.close();
Socket = null;
buttontitle = true;
Button.setText("連 接 服 務 器");
} else {
//如果有數據正常返回則進行處理顯示
textdata = new String(ReadBuffer,0,ReadBufferLengh,"GB2312");//原始編碼數據
edittotext.setText(new String(textdata.getBytes(),"UTF-8"));//轉爲UTF-8編碼後顯示在編輯框中
}
} catch (Exception e)
{
e.printStackTrace();
}
}
}
}
class ThreadSendData extends Thread //用線程發送數據
{
public void run()
{
try
{
OutputStream.write(datatoedit.getBytes()); //用輸出流發送數據
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
//信息框按鈕按下事件
public DialogInterface.OnClickListener click1 = new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
dialog.cancel();
}
};
}
以上就是動作代碼部分,這裏主要講Android Socket TCP客戶端怎麼發送一個字符串:
首先要通過輸出流Outputstream
1.在文件開頭定義輸出流Outputstream,初始化爲空(以下展示的代碼都放在主文件了,這裏只是拿出來分析)
OutputStream OutputStream = null;//定義數據輸出流,用於發送數據
InputStream InputStream = null;//定義數據輸入流,用於接收數據
2.定義我們要發送的字符串
String datatoedit;//發送buff
String data10="LED1OFF";
String data20="LED2OFF";
String data30="LED3OFF";
String data40="LED4OFF";
String data11="LED1ON";
String data21="LED2ON";
String data31="LED3ON";
String data41="LED4ON";
3.發送字符串
//用線程發送數據
class ThreadSendData extends Thread
{
public void run()
{
try
{
OutputStream.write(datatoedit.getBytes()); //用輸出流發送數據
}catch (Exception e){
e.printStackTrace();
}
}
}
這裏使用了線程發送數據,由於我在每個按鈕的出發工程中就已經將我要發送的對應字符串賦值給了變量datatoedit,所以在發送時直接發送了變量datatoedit
OutputStream.write(datatoedit.getBytes());
以上這一句就是講我們要發送的字符串寫到輸出流中
**注意注意:**TCP發送時發送的內容爲數組,所以要在字符串變量datatoedit後加上".getBytes()"目的是將字符串中的內容一個一個放到Bytes型數組中。
調試
點擊菜單欄上方綠色三角按鈕或直接Shift+F10進行編譯,設備自己選一個,安卓版本需要在6.0以上,因爲我的代碼是基於6.0寫的,得到下圖界面
之後嘗試連接PC啓動的網絡調試助手,點擊連接服務器後得到下圖
顯示連接成功之後測試各個按鈕功能,得到下圖
4個按鈕功能正常。
再次點擊連接服務器按鈕(目前已經變爲斷開連接),得到下圖消息
顯示客戶端離線,由上可知,所有按鈕功能正常,真是可喜可賀!!可喜可賀!!
生成APK
上述功能測試完成之後就能安裝使用了哦,點擊Android Studio菜單欄的Build→Build Bundle(s)/APK(s)→Build APK(s)稍等片刻之後就可以在項目文件目錄下\app\build\outputs\apk\debug文件夾中找到apk文件,這就是新鮮出爐的Android App了,將文件拖到自己的安卓設備即可使用。
寫博客不易,希望覺得對自己有用的同志轉載的時候附上我SCDN的ASWaterbenben的大名,謝謝大佬!!!!