Socketを使ってDSと通信してみる
わからないことだらけですが、初めてのAndroid、javaのプログラムに一歩踏み出したので、とりあえず何か作ってみようと思い、DSと繋げてみることにしました。
先ずはSocketを使ってDSと通信するところを作ってみたいと思います。
SurfaceViewを使う
基本的には、ActivityからSurfaceViewを呼び出して、そこでプログラミングしました。日経ソフトウェア6月号の記事を参考にさせていただいています。
import android.app.Activity; import android.os.Bundle; import android.view.Window; public class WifiTestActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //アプリケーションタイトルを非表示 requestWindowFeature(Window.FEATURE_NO_TITLE); // SurfaceViewを登録 setContentView(new WifiTestSurfaceView(this)); } @Override public void onResume(){ super.onResume(); //各メソッドはsuper.***と自分を最初に呼ぶのが決まり } @Override public void onPause(){ super.onPause(); //各メソッドはsuper.***と自分を最初に呼ぶのが決まり //一時停止の処理を記述 //ここではアプリを終了させる finish(); //onDestroy()が呼ばれる。 } @Override public void onDestroy(){ super.onDestroy(); //各メソッドはsuper.***と自分を最初に呼ぶのが決まり } }
メインプログラムはスレッドとして動かしたいので、スレッドプログラムを含むコールバック用のclassを作り、SurfaceViewからはこれを呼び出すようにしました。ここら辺も、日経ソフトウェア6月号の記事を参考にさせていただいています。
import android.content.Context; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; public class WifiTestSurfaceView extends SurfaceView { private WifiTestSurfaceHolderCallback cb = null; //コンストラクタ public WifiTestSurfaceView(Context context) { super(context); // TODO Auto-generated constructor stub SurfaceHolder holder = getHolder(); cb = new WifiTestSurfaceHolderCallback(); holder.addCallback(cb); } @Override public boolean onTouchEvent(MotionEvent event){ float x = event.getX(); //x座標の取得 float y = event.getY(); //y座標の取得 cb.getTouchPosition((int)x, (int)y); return true; } }
コールバックclass
コールバックのプログラムは、まだ不完全です。AndroidとDSをConnectionすることはできたのですが、Androidの受信側の作りこみが全くわからなくて、進んでいない状態です。
とりあえず、Connectionのところの説明だけ書きたいと思います。
下記はコールバックclassのimportと変数宣言のところです。SurfaceHolder.Callback(コールバック用)とRunnable(スレッド用)を実装しています。ここら辺も、日経ソフトウェア6月号の記事を参考にさせていただいています。
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketTimeoutException; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.util.Log; import android.view.SurfaceHolder; public class WifiTestSurfaceHolderCallback implements SurfaceHolder.Callback, Runnable { private SurfaceHolder holder = null; private Thread thread = null; private boolean isThreadrunning = true; private Socket sock = null; private BufferedWriter sockout = null; private BufferedReader sockin = null; private Paint paintf; private Paint paintb; private int x = 0; private int x1 = 0; private int y = 0; private int y1 = 0; private InputStream inputsock = null;
コンストラクタは下記です。文字を描きたいので、文字色と背景色用に2つのPaintインスタンスを作っています。とりあえず、これだけです。
// コンストラクタ public WifiTestSurfaceHolderCallback(){ paintf = new Paint(); paintf.setStyle(Style.FILL); paintf.setARGB(255, 255, 255, 255); paintf.setTextSize(16); paintb = new Paint(); paintb.setStyle(Style.FILL); paintb.setARGB(255, 0, 0, 0); }
surfaceCreated
surfaceCreatedはSurfaceが作られるときに呼び出される関数です。AvtivityがonCreate()するときに呼ばれるはずなので、ここにsocketの処理を書きました。
192.168.24.63(DSのIPアドレス)の8520ポートに接続に行きます。DSの方はこのポートへのアクセスを待たせています。
5000msの待ち時間で接続しに行きます。タイムアウトした場合、メッセージを出し、isFinish=trueにします。
そして、isFinish==trueのときは、socketをcloseし、falseのときは、threadを起動します。
public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub this.holder = holder; boolean isFinish = false; try { // ソケットの作成 String host = "192.168.24.63"; int port = 8520; sock = new Socket(); SocketAddress adr = new InetSocketAddress(host,port); sock.connect(adr, 5000); sockout = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream())); inputsock = sock.getInputStream(); } catch (SocketTimeoutException e) { Canvas canvas = holder.lockCanvas(); // ロックをかける drawOnCanvas(canvas, "接続がタイムアウトしました","再度起動してください"); older.unlockCanvasAndPost(canvas); // ロックを解除 isFinish = true; e.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } if( isFinish==true){ try { // ソケットのクローズ sock.close(); } catch (Exception ex) { ex.printStackTrace(); } } else{ // スレッドの開始 thread = new Thread(this); thread.start(); } }
surfaceDestroyed
surfaceDestroyedは、Activityを終了させるときに呼び出される関数です。このプログラムでは、ActivityがonPause()してもonDestroy()が呼ばれるように作っているので、画面が消えれば呼ばれることになります。
threadが動いていれば、スレッドを切ります。日経ソフトウェア6月号の記事を参考にさせていただいています。isThreadrunning = false;はif文の中でもいいですね。
そして、Socketをクローズします。sockout.close();とかありますが、プログラムはまだ未完成です。
public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub boolean retry = true; synchronized (this.holder) { isThreadrunning = false; } if( thread!=null ){ while (retry) { try { thread.join(); retry = false; } catch (InterruptedException e) { } } thread = null; } try { // ソケットのクローズ sockout.close(); sock.close(); } catch (Exception ex) { ex.printStackTrace(); } }
スレッド
スレッドはrun()関数が起動します。プログラムはisThreadrunningがtrueの間、動作し続ける形になっています。ここら辺も、日経ソフトウェア6月号の記事を参考にさせていただいています。
プログラム的にはxとyの値をせっせとsocketでDSに送信します。DSからの受信部分がうまく動かないので、ソースから削除しています。本当はバイナリで送信したいのですが、javaがわからないので、テキストで送信しています。今後、勉強したいと思います。とりあえず、何を送信したかを、drawOnCanvas()を用いてSurfaceViewに表示しています。
@Override public void run() { // TODO Auto-generated method stub String outtxt = ""; while (isThreadrunning) { synchronized (holder) { if( x!=x1 || y!=y1){ if( x>999 ){ x = 999; } else if( x<0 ){ x = 0; } if(y>999){ y=999; }else if( y<0 ){ y = 0; } outtxt = String.format("%03d", x) + "," + String.format("%03d", y); try { sockout.write(outtxt); sockout.flush(); x1 = x; y1 = y; } catch (Exception ex) { ex.printStackTrace(); } } } // 描画の処理 Canvas canvas = holder.lockCanvas(); // ロックをかける drawOnCanvas(canvas, intxt, outtxt); holder.unlockCanvasAndPost(canvas); // ロックを解除 } }
drawOnCanvas()
SurfaceViewに文字を表示します。黒色で画面を塗りつぶして、文字を表示しているだけです。
public void drawOnCanvas(Canvas canvas, String txt1, String txt2){ canvas.drawPaint(paintb); //画面黒塗り canvas.drawText( txt1, 0, 16, paintf); //txt1表示 canvas.drawText( txt2, 0, 48, paintf); //txt2表示 }
タッチ座標の取得
SurfaceViewがタッチされたとき、コールバックされてその座標を取得する関数です。
public void getTouchPosition(int x, int y){ this.x = x; this.y = y; }
本当にやりたいことリスト
(ブログの終わりにやりたいことを書いておきたいと思います)
- 求職活動・・・このブログで興味を持った人一声かけてください。m(_ _)m
- Androidプログラム・・・始めつつあります。
- Web系のプログラム