1.這是安卓APP實現的主活動------MainActivity.java
讀這篇文章前,最好先閱讀這篇索引文章
如果一點安卓基礎都沒有的,麻煩請先入門,另外學一學Android Studio的基礎知識。
APP使用的是socket框架,通過tcp/ip協議與單片機通信。
由於我寫這個代碼的時候是大四第一學期剛開學臨時學的,所以寫的不是很好,代碼也沒有優化,包括UI也不美觀,僅僅是實現了應有的功能而已。
對於沒有加註釋很抱歉,但是代碼很短,基本上學過Java和安卓基礎的都能看懂的,相信我。
如果你是一個安卓小白,並且已經安卓好Android Studio了,學會如何創建一個empty Activity了的話,那就創建好空的Activity之後,把對應的MainActivity.java和activity_main.xml代碼替換成我給出來的代碼就好啦!
package com.example.myclient;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private Button startButton,sendButtonClient,sendButtonClient1,sendButtonClient2,sendButtonClient3;
private EditText IPText,editMsgTextClient;
private Context mContext;
private boolean isConnecting=false;
private Thread mThreadClient=null;
private Socket mSocketClient=null;
static BufferedReader mBufferedReaderClient=null;
static PrintWriter mPrintWriterClient=null;
static int a=1;
private String recvMessageClient="";
private static TextView recvText,recvText1,recvText2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext=this;
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build()
);
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
IPText=(EditText) findViewById(R.id.IPText);
IPText.setText("172.16.2.184:8086");
startButton=(Button) findViewById(R.id.StartConnect);
startButton.setOnClickListener(StartClickListener);
//editMsgTextClient=(EditText) findViewById(R.id.clientMessageText);
//editMsgTextClient.setText("UP");
sendButtonClient=(Button) findViewById(R.id.SendButtonClient);
sendButtonClient.setOnClickListener(SendClickListenerClient);
sendButtonClient1=(Button) findViewById(R.id.SendButtonClient1);
sendButtonClient1.setOnClickListener(SendClickListenerClient1);
sendButtonClient2=(Button) findViewById(R.id.SendButtonClient2);
sendButtonClient2.setOnClickListener(SendClickListenerClient2);
sendButtonClient3=(Button) findViewById(R.id.SendButtonClient3);
sendButtonClient3.setOnClickListener(SendClickListenerClient3);
recvText=(TextView) findViewById(R.id.tv1);
recvText.setMovementMethod(ScrollingMovementMethod.getInstance());
recvText1=(TextView) findViewById(R.id.textView3);
recvText1.setMovementMethod(ScrollingMovementMethod.getInstance());
recvText2=(TextView) findViewById(R.id.textView4);
recvText2.setMovementMethod(ScrollingMovementMethod.getInstance());
}
private OnClickListener StartClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(isConnecting)
{
isConnecting = false;
try
{
if(mSocketClient!=null)
{
mSocketClient.close();
mSocketClient = null;
mPrintWriterClient.close();
mPrintWriterClient = null;
}
}catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
mThreadClient.interrupt();
startButton.setText("開始連接");
IPText.setEnabled(true);
recvText.setText("信息:\n");
}else
{
isConnecting=true;
startButton.setText("停止連接");
IPText.setEnabled(false);
mThreadClient = new Thread(mRunnable);
mThreadClient.start();
}
}
};
private OnClickListener SendClickListenerClient = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(isConnecting&&mSocketClient!=null)
{
//String msgText = editMsgTextClient.getText().toString();
String msgText ="c1\n";
if(msgText.length()<=0)
{
Toast.makeText(mContext, "發送內容不能爲空!", Toast.LENGTH_SHORT).show();
}else
{
try
{
mPrintWriterClient.print(msgText);
mPrintWriterClient.flush();
}catch (Exception e) {
// TODO: handle exception
Toast.makeText(mContext, "發送異常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}else
{
Toast.makeText(mContext, "沒有連接", Toast.LENGTH_SHORT).show();
}
}
};
private OnClickListener SendClickListenerClient1 = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(isConnecting&&mSocketClient!=null)
{
//String msgText = editMsgTextClient.getText().toString();
String msgText ="c0\n";
if(msgText.length()<=0)
{
Toast.makeText(mContext, "發送內容不能爲空!", Toast.LENGTH_SHORT).show();
}else
{
try
{
mPrintWriterClient.print(msgText);
mPrintWriterClient.flush();
}catch (Exception e) {
// TODO: handle exception
Toast.makeText(mContext, "發送異常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}else
{
Toast.makeText(mContext, "沒有連接", Toast.LENGTH_SHORT).show();
}
}
};
private OnClickListener SendClickListenerClient2 = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(isConnecting&&mSocketClient!=null)
{
//String msgText = editMsgTextClient.getText().toString();
String msgText ="t1\n";
if(msgText.length()<=0)
{
Toast.makeText(mContext, "發送內容不能爲空!", Toast.LENGTH_SHORT).show();
}else
{
try
{
mPrintWriterClient.print(msgText);
mPrintWriterClient.flush();
}catch (Exception e) {
// TODO: handle exception
Toast.makeText(mContext, "發送異常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}else
{
Toast.makeText(mContext, "沒有連接", Toast.LENGTH_SHORT).show();
}
}
};
private OnClickListener SendClickListenerClient3 = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(isConnecting&&mSocketClient!=null)
{
//String msgText = editMsgTextClient.getText().toString();
String msgText ="t0\n";
if(msgText.length()<=0)
{
Toast.makeText(mContext, "發送內容不能爲空!", Toast.LENGTH_SHORT).show();
}else
{
try
{
mPrintWriterClient.print(msgText);
mPrintWriterClient.flush();
}catch (Exception e) {
// TODO: handle exception
Toast.makeText(mContext, "發送異常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}else
{
Toast.makeText(mContext, "沒有連接", Toast.LENGTH_SHORT).show();
}
}
};
//線程:監聽服務器發來的消息
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
String msgText = IPText.getText().toString();
if(msgText.length()<=0)
{
recvMessageClient="IP不能爲空!\n";//消息換行
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
return;
}
int start = msgText.indexOf(":");
if((start==-1)||(start+1>=msgText.length()))
{
recvMessageClient = "IP地址不合法\n";
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
return;
}
String sIP= msgText.substring(0,start);
String sPort = msgText.substring(start+1);
int port = Integer.parseInt(sPort);
Log.d("gjz", "IP"+sIP+":"+port);
try
{
//連接服務器
mSocketClient = new Socket(sIP,port);
//取得輸入、輸出流
mBufferedReaderClient=new BufferedReader(new InputStreamReader(mSocketClient.getInputStream()));
mPrintWriterClient=new PrintWriter(mSocketClient.getOutputStream(),true);
recvMessageClient="已經連接到智能衣櫃!\n";
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
}catch (Exception e) {
// TODO: handle exception
recvMessageClient = "連接IP異常:" + e.toString() + e.getMessage() + "\n";//消息換行
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
return;
}
char[] buffer = new char[256];
int count = 0;
while(isConnecting)
{
try
{
if((count = mBufferedReaderClient.read(buffer))>0)
{
recvMessageClient = getInfoBuff(buffer,count)+"\n";
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
}
}catch (Exception e) {
// TODO: handle exception
recvMessageClient = "接收異常:" + e.getMessage() + "\n";//消息換行
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
}
}
}
};
Handler mHandler = new Handler()
{
public void handleMessage(Message msg)
{
super.handleMessage(msg);
if(msg.what==1)
{
char []arrs=null;
while (a>0){
recvText.append(recvMessageClient);//刷新
a--;
}
arrs=recvMessageClient.toCharArray();
if (arrs[0]=='1'&&arrs[8]>=7){
//recvText.append("溫溼度:"+arrs[5]+arrs[6]+"℃"+' '+arrs[8]+arrs[9]+"%\n");//刷新
//recvText1.append(arrs[5] + arrs[6] + "℃" + ' ' + arrs[8] + arrs[9] + "%\n");
recvText1.setText("溫溼度: "+arrs[5] + arrs[6] + "℃" + ' ' + arrs[8] + arrs[9] + "% 差,請除溼\n");
}
else if (arrs[0]=='1'&&arrs[8]<7){
recvText1.setText("溫溼度: "+arrs[5] + arrs[6] + "℃" + ' ' + arrs[8] + arrs[9] + "% 良\n");
}
else if (arrs[0]=='2'&&arrs[6]<'3'){
//recvText2.append(arrs[5]+arrs[6]+arrs[7]+"%\n");//刷新
recvText2.setText("氣體濃度:"+arrs[5]+arrs[6]+arrs[7]+"% 良\n");
}
else if (arrs[0]=='2'&&arrs[5]>'3'){
//recvText2.append(arrs[5]+arrs[6]+arrs[7]+"%\n");//刷新
recvText2.setText("氣體濃度:"+arrs[5]+arrs[6]+arrs[7]+"% 差,請通風\n");
}
//recvText.append("衣櫃助手:"+recvMessageClient);//刷新
}
};
};
private String getInfoBuff(char[] buff,int count)
{
char[] temp = new char[count];
for (int i = 0; i < count; i++) {
temp[i]=buff[i];
}
return new String(temp);
}
}
2.這個是xml,溫溼度和氣體濃度初始值默認爲0;當接收到單片機的發送過來的數據後,對應的數值會更新!
<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
android:background="#99cccc"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="智能衣櫃助手"
android:textSize="20dip" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/textView1">
<EditText
android:id="@+id/IPText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="請輸入衣櫃服務端的IP地址" />
<Button
android:id="@+id/StartConnect"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="開始連接" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="通風"
android:id="@+id/textView" />
<Button
android:id="@+id/SendButtonClient"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="開" />
<Button
android:id="@+id/SendButtonClient1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="關" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="抽溼"
android:id="@+id/textView2" />
<Button
android:id="@+id/SendButtonClient2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="開" />
<Button
android:id="@+id/SendButtonClient3"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="關" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/tv1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="22dip" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="溫溼度:0℃ 0%"
android:id="@+id/textView3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="氣體濃度:0%"
android:id="@+id/textView4" />
</LinearLayout>
</RelativeLayout>
3.如果你很熟悉Android Studio的話,也可以直接使用我的全部源碼!
4.關於APP的一些應該要優化的地方:
(1)邏輯:因爲之前剛入門,所以可能在一些語句的邏輯上會有問題。但是不影響功能實現。
(2)當APP接收到單片機傳過來的數據時,點擊按鈕會不靈敏,也就是說,點擊按鈕沒有用,這是因爲WiFi模塊的接收函數已經被單片機那邊佔用了,不能同時再接收來自APP的數據,這個問題也困擾了我很久,我最後是在單片機那裏把發送數據給APP的頻率降低一點,改成每10秒發一次,就優化了這個問題,但是我現在還沒有別的更好的辦法去解決這個問題的根源,我也問過了老師,他也不知道…那就留給你們幫我想把,哈哈哈…
(3)界面太簡陋,因爲只有一個界面,所有功能都集成在一個界面了…
(4)暫時還沒有增加用戶和服務器數據庫的功能,這些在後面的章節我會說。