Android - Socket 功能在 Service 中實現【這才是實際的使用方式】

來源:互聯網
上載者:User

標籤:

前幾天學習了 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 }

 

Android - Socket 功能在 Service 中實現【這才是實際的使用方式】

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.