在Android SDK撰寫Socket UDP,讓手機與各種裝置通訊摟!
在網路上搜尋Android的UDP通訊,看到很多文章都是失敗收場,甚至有些文章直接寫Android不支援UDP通訊協定,不死心的我決定要再來好好研究,果然皇天不付有心人,在零碎的資料整合後終於完成了Android的UDP程式了,以下就由我一步一步教大家怎麼做吧!
首先,必須要先釐清一個事情,不論在Windows的.Net平台或是Android SDK中,一個軟體在執行時就會產生一個程序(大陸叫進程,Process),一個程序中可以擁有多個執行緒(大陸叫線程,Thread),在程式的撰寫中,MAIN函數會在主執行緒中運作,連通使用者介面(UI)也被賦予在主執行緒中,然而,在寫通訊程式的時候會利用多執行緒的方式來撰寫,原因是主執行緒的工作是負責MAIN以及UI的運作,讓副執行緒運作一個不間斷且持續運作的迴圈,以便監聽通訊的工作,所以在這個範例中,我們會使用到Android的多執行緒寫作技巧。
在Android的多執行緒寫作技巧中,必須搭配其他技術才得以讓副執行緒去變更由主執行緒負責的UI,這個技術就是Handler,不過在本篇中我們專注在UDP通訊的部分,其他如Thread以及Handler將會另外新增篇幅來向大家說明,接著就進入主題吧!
首先拉一個簡單的介面,由EditText、Button、TextView組成,如下圖:
【main.xml】
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<EditText
android:id="@+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<requestFocus />
</EditText>
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="SEND" android:onClick="bt1_OnClick"/>
<TextView
android:id="@+id/TextView01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:text="@string/hello" />
</LinearLayout>
【AndroidManifest.xml】
在這個XML檔案中增加新的網路設定,以便讓模擬器可以使用正常的網路通訊功能,如下所示:
<uses-permission android:name="android.permission.INTERNET"/>
【AndroidSample_UdpActivity.java】
package peter.crispkid.namespace;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.atomic.AtomicBoolean;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.Time;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class AndroidSample_UdpActivity extends Activity {
TextView tv1;
Button bt1;
EditText et1;
Time t;
private static final int UDP_SERVER_PORT = 11111;
Handler handler=new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String msgString = (String)msg.obj;
t.setToNow();
tv1.setText(String.valueOf(t.hour)+":"+
String.valueOf(t.minute)+":"+
String.valueOf(t.second)+"=>"+msgString+"\n"+tv1.getText().toString());
}
};
AtomicBoolean isRunning=new AtomicBoolean(false);
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv1=(TextView) findViewById(R.id.TextView01);
bt1=(Button) findViewById(R.id.button1);
et1=(EditText) findViewById(R.id.editText1);
t=new Time();
}
public void bt1_OnClick(View view)
{
try {
String sendData = et1.getText().toString();
InetAddress serverAddr = InetAddress.getByName("192.168.1.6");
DatagramPacket dp;
dp = new DatagramPacket(sendData.getBytes(), sendData.length(), serverAddr, UDP_SERVER_PORT);
try {
ds.send(dp);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
DatagramSocket ds = null;
public void onStart() {
super.onStart();
tv1.setText("START...");
Thread background=new Thread(new Runnable() {
public void run() {
try {
String data;
byte[] recevieData = new byte[1024];
DatagramPacket dp = new DatagramPacket(recevieData, recevieData.length);
ds = new DatagramSocket(UDP_SERVER_PORT);
for (;isRunning.get();) {
Thread.sleep(100);
ds.receive(dp);
data = new String(recevieData, 0, dp.getLength());
handler.sendMessage(handler.obtainMessage(1,data));
}
}
catch (Throwable t) {
// just end the background thread
}
}
});
isRunning.set(true);
background.start();
}
public void onStop() {
super.onStop();
isRunning.set(false);
}
}
副執行緒負責維持通訊監聽的功能,在Android SDK中的規定,副執行緒若要更改UI的內容,必須使用Handler的Message的技巧來與UI做溝通。
當我們將上述程式都撰寫完畢後,即可開始執行Debug,當模擬器開始運作並載入APK後,在HOST端開啟命令提示字元,使用Telnet登入到Android模擬器內,並鍵入相關命令,如下圖:
該命令的結構是=>redir add <tup/udp>:port:port,這段命令代表的是將Host端的Port轉送到Android端的Port,否則在模擬器內的UDP Server將無法收到外部傳進來的通訊資料。
以上就是今天的教學了唷,若有細節不懂得,請留言詢問唷,或請跟我說哪邊需要更精進唷^^
PeterDotNetAndroidUDP12082601.zip