前几天学习了 Android 下 Socket 编程,由于个人是刚开始学习 Android 相应的知识。所以特意将学习中的代码与过程,写成 BLOG,如:http://blog.csdn.net/91program/article/details/39177401
学习 Socket 编程是有目的的,需要完成在手机与 PC 之间的通讯。通讯的内容是将手机上播放的 MP3 信息,通过 Socket 传输到 PC 端。
在参考网上相关 Socket 的文章后,基本上完成了 Socket 功能。所以就继续学习 Android 下音乐播放器的实现。在实现音乐播放器过程中,发现由于音乐播放器至少要有播放列表和正在播放两个 Activity,这样问题就来了:
(1). Socket 只是在第一个 Activity 中实现了,当这个 Activity 活动时没有问题。但此 Activity 非活动时,不能处理 Socket。
(2). 当反复进入第一个 Activity 时,会出现 Socket 初始化报错的问题。出现这样的错误,是由于 Sokcet 的初始化放在第一个 Activity 的 onCreate 中。

由于在做音乐播放器时使用了 Service,所以想到用 Serivce 来处理 Socket 应该没有问题。但是否有其它的方法呢?由于个人是刚刚接触 Android 编程,就不能确定这个问题了!
在 CSDN Android 论坛提问,帖子:http://bbs.csdn.net/topics/390884423。得到的答案是:(1) Serivce; (2) 也可以更改activity的启动方式,让串口不重复创建。显然,第二种方法还没有接触过。采用第一种 Serivce 来实现更可靠一些。

首先,实现 Socket Service。

package com.jia.leozhengfirstapp;import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.net.ServerSocket;import java.net.Socket;import android.app.Service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.IBinder;import android.util.Log;public class SocketService extends Service {  private Socket clientSocket = null;  private ServerSocket mServerSocket = null;  private SocketAcceptThread socketAcceptThread = null;  private SocketReceiveThread socketReceiveThread = null;  private SocketReceiver socketReceiver;  public static final String SOCKER_ACTION = "com.jia.Socket.Control";  public static final String SOCKER_RCV = "com.jia.Socket.ReceiveStr";  private boolean stop = true;  @Override  public IBinder onBind(Intent intent) {    // TODO Auto-generated method stub    return null;  }   @Override  public void onCreate() {          super.onCreate();          Log.d("service", "socket service created");          socketReceiver = new SocketReceiver();          IntentFilter filter = new IntentFilter();          filter.addAction(SOCKER_ACTION);          registerReceiver(socketReceiver, filter);          socketAcceptThread = new SocketAcceptThread();            // 开启 Socket 监听线程            socketAcceptThread.start();   }  @Override  public void onStart(Intent intent, int startId) {     Log.d("service", "socket service start");  }  @Override  public void onDestroy() {  Log.d("service", "socket service destroy!");  }  public class SocketReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {      String action = intent.getAction();            if(action.equals(SOCKER_ACTION)) {              String sub_action = intent.getExtras().getString("ACTION");              if(sub_action.equals("reconnect")) {                Log.d("service", "socket service: reconnect.");                 socketAcceptThread = new SocketAcceptThread();                  // 开启 Socket 监听线程                  socketAcceptThread.start();              }            }    }  }  private class SocketAcceptThread extends Thread  {       @Override       public void run()       {         Log.d("service", "socket service - SocketAcceptThread::run");           try {               // 实例化ServerSocket对象并设置端口号为 12589               mServerSocket = new ServerSocket(12589);           } catch (IOException e) {               // TODO Auto-generated catch block               e.printStackTrace();           }           try {               // 等待客户端的连接(阻塞)               clientSocket = mServerSocket.accept();           } catch (IOException e) {               // TODO Auto-generated catch block               e.printStackTrace();           }           socketReceiveThread = new SocketReceiveThread(clientSocket);           stop = false;           // 开启接收线程           socketReceiveThread.start();             Intent sendIntent = new Intent(SOCKER_RCV);             sendIntent.putExtra("action", "ClientIP");             sendIntent.putExtra("content", clientSocket.getInetAddress().getHostAddress());             // 发送广播,将被Activity组件中的BroadcastReceiver接收到             sendBroadcast(sendIntent);       }   }   private class SocketReceiveThread extends Thread   {       private InputStream mInputStream = null;       private byte[] buf;       private String str = null;       Socket sUsed;       SocketReceiveThread(Socket s)       {         Log.d("service", "socket service - SocketReceiveThread");           try {               // 获得输入流               this.mInputStream = s.getInputStream();               sUsed = s;           } catch (IOException e) {               // TODO Auto-generated catch block               e.printStackTrace();           }       }       @Override       public void run()       {         Log.d("service", "socket service - SocketReceiveThread::run");           while((!stop) && (!mServerSocket.isClosed()))           {               this.buf = new byte[2048];               // 读取输入的数据(阻塞读)               try {                   this.mInputStream.read(buf);               } catch (IOException e1) {                   // TODO Auto-generated catch block                   e1.printStackTrace();               }               // 字符编码转换               try {                   this.str = new String(this.buf, "GB2312").trim();               } catch (UnsupportedEncodingException e) {                   // TODO Auto-generated catch block                   e.printStackTrace();               }               Intent sendIntent = new Intent(SOCKER_RCV);               sendIntent.putExtra("action", "RcvStr");               sendIntent.putExtra("content", this.str);               // 发送广播,将被Activity组件中的BroadcastReceiver接收到               sendBroadcast(sendIntent);           }       }   }}

在每个 Activity 中处理 SOCKER_RCV action,以响应 Socket 状态的变化和接收到数据。
Service 与 Activity 之间通讯需要使用到广播: Broadcast。
(1) 在 Activity 中定义全局的变量,如下:

1 public static final String SOCKER_ACTION = "com.jia.Socket.Control";2 public static final String SOCKER_RCV = "com.jia.Socket.ReceiveStr";3 4 SocketReceiver socketReceiver

(2) 在 Activity 的 onCreate 中注册广播和启动 Socket Service,如下:

1 socketReceiver = new SocketReceiver();2 IntentFilter socketIntentFilter = new IntentFilter();3 socketIntentFilter.addAction(SOCKER_RCV);4 registerReceiver(socketReceiver,socketIntentFilter);5 6 Intent socketIntent = new Intent();7 socketIntent.setClass(MainActivity.this, SocketService.class);8 startService(socketIntent);       // 启动  Socket 服务

(3) SocketReceiver 是继承自 BroadcastReceiver 的类,实现如下:

 1 public class SocketReceiver extends BroadcastReceiver { 2  3  4   @Override 5   public void onReceive(Context context, Intent intent) { 6     // TODO Auto-generated method stub 7     String action = intent.getAction(); 8           if(action.equals(SOCKER_RCV)) { 9             String url = intent.getExtras().getString("action");10             if(url.equals("ClientIP")) {11               String strIP = intent.getExtras().getString("content");12             }13             else if(url.equals("RcvStr")) {14               String strContent = intent.getExtras().getString("content");15             }16             else if(url.equals("Disconnect")) {17               String strContent = intent.getExtras().getString("content");18             }19         }20     }21 }

(4) Socket 功能实现后,测试时发现客户端(也就是 PC 端)断开时手机端未检测到 Socket 连接断开。
以前使用 WinCE 时,Socket(TCP) 断开时,无论是客户端、还是服务器都可以检测到 TCP 断开的事件,并处理。但 Android 下的 Socket 编程机制竟然没有这个东东。
一,测试时发现当 PC 端断开后,手机端的服务程序在执行到下面的代码段时不会阻塞,且函数的返回值是: -1。
二,在网上查找发现这个问题是 Android 下 Socket 都有的问题,可以通过发心跳包来处理。
所以将下面这段代码:

 1 // 读取输入的数据(阻塞读) 2 try { 3     this.mInputStream.read(buf); 4 } catch (IOException e1) { 5     // TODO Auto-generated catch block 6     e1.printStackTrace(); 7 } 8 修改为如下的代码: 9 try {10     int length = this.mInputStream.read(buf);11     if(-1 == length) {12       try {13         sUsed.sendUrgentData(0xff);14       }15       catch(Exception ex) {16         // 链接已断开17         Log.v("service", "disconnect!!!");18         stop = true;19         if(null != mServerSocket) {20           mServerSocket.close();21         }22 23 24         Intent sendIntent = new Intent(SOCKER_RCV);25         sendIntent.putExtra("action", "Disconnect");26         sendIntent.putExtra("content", "read is -1 & Urgent Exception!");27         sendBroadcast(sendIntent);28 29 30         continue;31       }32     }33 } catch (IOException e1) {34     // TODO Auto-generated catch block35     e1.printStackTrace();36 }

更多相关文章

  1. 从零开始--系统深入学习android(已完成部分的目录--带链接)
  2. 一步步探索学习Android(安卓)Touch事件分发传递机制(二)
  3. .Net 转战 Android(安卓)4.4 日常笔记(9)--常用组件的使用方法[附
  4. Android(安卓)学习之《第一行代码》第二版 笔记(二十)播放多媒体文
  5. Android学习笔记:Preference的使用
  6. Android开发学习 -- Day11 BroadcastReceiver
  7. Android(安卓)学习笔记(二七):Menu
  8. Android学习笔记(三三):Activity生命周期
  9. android中的Context(android内核学习记录)

随机推荐

  1. Android显示GIF动画完整示例(二)
  2. 使用Android Dropbox API检查Dropbox上是
  3. 【边做项目边学Android】手机安全卫士04_
  4. android开发中如何从当前页面返回上一页
  5. net. unknownhostexception:无法解析主机
  6. 【Android 开发教程】通过编码实现发送短
  7. Android功能模块化之网络连接状态判断
  8. Android Studio在连接手机时候,出现"Inst
  9. 跟核心虚拟机Dalvik说再见 Android Runti
  10. 实现微信布局的四种方式(一)