基於語音控制的智能衣櫃系統——安卓手機APP的實現

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)暫時還沒有增加用戶和服務器數據庫的功能,這些在後面的章節我會說。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章