編輯:關於Android編程
Android與服務器之間的通訊方式主要有兩種。一種是Http通訊 , 一種是Socket通訊。兩者最大的差異在於,Http連接使用的是“請求---響應方式”,即在請求是建立連接通道,當客戶端向服務器發送請求後,服務器端才能向客戶端返回數據。而Socket則是在雙方建立連接後就直接進行數據傳輸,在連接時可實現信息的主動推送,而不需要每次由客戶端向服務端發送請求。
什麼是Socket?又稱套接字,是一種抽象層。在程序內部提供了與外界通訊的端口,即端口信息。通過建立Socket連接,可為通訊雙方的傳輸提供通道。Socket的主要特點有數據丟失率低,使用簡單且易於移植。
本案例是基於TCP協議的Socket。服務端首先聲明一個ServerSocket對象並且指定端口號。然後調用ServerSocket的accept()方法接收客戶端的數據。accept()方法在沒有數據進行接收的處於堵塞狀態。(Socketsocket=serversocket.accept()),一旦接收到數據,通過inputstream讀取接收的數據。
客戶端創建一個Socket對象,指定服務器端的ip地址和端口號(Socketsocket=newSocket("172.168.10.108",8080);),通過inputstream讀取數據,獲取服務器發出的數據(OutputStreamoutputstream=socket.getOutputStream()),最後將要發送的數據寫入到outputstream即可進行TCP協議的socket數據傳輸。
項目結構:
2. IMService.class
public class IMService extends Service { static Communication communication; public static String messageTag="com.gys.im.CYEJIMActivity"; public static Notification notification; public static int messageId = 10000; private NotificationManager mNM; boolean isconnected; Timer timer=new Timer(); @Override public void onCreate() { // TODO Auto-generated method stub communication=Communication.newInstance(); communication.setReceiver(this); mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notification=new Notification(R.drawable.ic_launcher, "", System.currentTimeMillis()); notification.number=1; timer.schedule(timerTask, 1000, 2000); } public Handler handler= new Handler() { public void handleMessage(Message msg) { String message=msg.obj.toString(); if(message.equals("start\n")) { start_check_in(); }else { Intent intent = new Intent(messageTag); intent.putExtra("message", message); IMService.this.sendBroadcast(intent); } } }; public TimerTask timerTask=new TimerTask() { @Override public void run() { // TODO Auto-generated method stub isconnected=checkNetwork(); if(!isconnected) { showNotification("",""); } } }; /** * 添加內容到發送消息隊列 * @param str */ public static void addPacket(String str) { communication.addPacket(str); } public static void wakeUp() { communication.wakeUp(); } /** * 開始發送心跳 */ protected void start_check_in() { communication.start_check_in(); } public boolean checkNetwork() { boolean flag = false; ConnectivityManager cwjManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); if (cwjManager.getActiveNetworkInfo() != null) { flag = cwjManager.getActiveNetworkInfo().isAvailable(); } return flag; } private void showNotification(String statusInfo,String messageContent) { PendingIntent contentIntent = PendingIntent.getActivity(this,0,null,0); notification.when=System.currentTimeMillis(); notification.tickerText=statusInfo; notification.setLatestEventInfo(this,"test",messageContent, null); notification.contentIntent=contentIntent; notification.vibrate = new long[] {100, 250, 100, 500}; messageNotificationAdd(messageId, notification); } /*add a nonotification*/ public void messageNotificationAdd(int notificationNo,Notification notification){ try { mNM.notify(notificationNo,notification); }catch(Exception e) { e.printStackTrace(); } notification.number++;//number 增加後,可以與以前的notification區分開來 } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); mNM.cancel(messageId); } @Override public void onLowMemory() { // TODO Auto-generated method stub super.onLowMemory(); } @Override public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub super.onStart(intent, startId); } @Override public boolean onUnbind(Intent intent) { // TODO Auto-generated method stub return super.onUnbind(intent); } @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } }
public class Communication { private NetTransportWorker transportWorker; private MessageWorker messageWorker; private static Communication instance; private Communication() { transportWorker = new NetTransportWorker(); transportWorker.start(); messageWorker = new MessageWorker(transportWorker); messageWorker.start(); } public static Communication newInstance() { if (instance == null) instance = new Communication(); return instance; } public NetTransportWorker getTransportWorker() { return transportWorker; } public MessageWorker getMessageWorker() { return messageWorker; } public void setReceiver(IMService service) { transportWorker.setRecever(service); } // public void addReceiveInfoListener(ReceiveInfoListener listener) { // transportWorker.addReceiveInfoListener(listener); // } // // public void removeReceiveInfoListener(ReceiveInfoListener listener) { // transportWorker.removeReceiveInfoListener(listener); // } public void reconnect() { transportWorker.notify(); } private boolean sendDataToServer(String packet) { try { if (transportWorker.writeBuf(packet.getBytes("UTF8"))) return true; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } /** 如果從不活動界面切換到聊天界面,此方法返回所有隊列裡面的信息數據包 **/ public QueuegetReceivePackets() { return transportWorker.receiveQueue; } public void addPacket(String packet) { messageWorker.addPacket(packet); } public void wakeUp() { messageWorker.wakeUp(); } public void start_check_in() { messageWorker.start_check_in(); } public String newSessionID() { return String.valueOf(System.currentTimeMillis()); } }
4.MessageWorker.class:
public class MessageWorker extends Thread { protected NetTransportWorker worker; protected QueuesendQueue; protected Timer timer; protected TimerTask task; // 10S發送一個確認在線的報到 protected final long delay = 30000; protected MessageWorker(final NetTransportWorker worker) { this.worker = worker; sendQueue = new ConcurrentLinkedQueue (); task = new TimerTask() { @Override public void run() { // TODO Auto-generated method stub String packet = "hello\n"; addPacket(packet); wakeUp(); } }; } public static String getLocalHostIp() { String ipaddress = "no_data"; try { Enumeration en = NetworkInterface .getNetworkInterfaces(); // 遍歷所用的網絡接口 while (en.hasMoreElements()) { NetworkInterface nif = en.nextElement();// 得到每一個網絡接口綁定的所有ip Enumeration inet = nif.getInetAddresses(); // 遍歷每一個接口綁定的所有ip while (inet.hasMoreElements()) { InetAddress ip = inet.nextElement(); if (!ip.isLoopbackAddress() && InetAddressUtils.isIPv4Address(ip .getHostAddress())) { return ipaddress =ip.getHostAddress(); } } } } catch (SocketException e) { System.out.print("獲取IP 失敗"+e.toString()); e.printStackTrace(); } return ipaddress; } protected void start_check_in() { if(timer==null) { timer=new Timer(); timer.schedule(task, delay, delay); } } public void addPacket(String packet) { sendQueue.add(packet); wakeUp(); } public synchronized void wakeUp() { notify(); } @Override public synchronized void run() { // TODO Auto-generated method stub while (true) { try { while (sendQueue.size() > 0) { String packet = sendQueue.peek(); if (worker.writeBuf(packet.getBytes("UTF8"))) { sendQueue.poll(); }else { sendQueue.clear(); } } wait(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
public class NetTransportWorker extends Thread { protected Socket socket = null; protected static final int CONNECT_TIMEOUT = 10000; protected static final int READ_TIMEOUT = 60000; protected static final int RECONNECT_TIME = 30000; protected ByteArrayOutputStream readByte; protected DataOutputStream readData; static { java.lang.System.setProperty("java.net.preferIPv6Addresses", "true"); }; protected final byte connect = 1; protected final byte running = 2; protected byte state = connect; protected boolean onWork;// 是否工作狀態 public static final String sysError = "與服務器連接斷開了,馬上重新連接!"; protected IMService service; protected QueuereceiveQueue; String packet; DataOutputStream output; DataInputStream input; protected NetTransportWorker() { onWork = true; readByte = new ByteArrayOutputStream(); readData = new DataOutputStream(readByte); receiveQueue = new ConcurrentLinkedQueue (); } protected void setRecever(IMService service) { this.service=service; } @Override public void run() { // TODO Auto-generated method stub while (onWork) { switch (state) { case connect: connect(); break; case running: running(); break; } } } private synchronized void running() { try { byte[] buffer=new byte[1024]; ByteArrayOutputStream baos=new ByteArrayOutputStream(); byte[] reallyByte; int number; while((number=input.read(buffer, 0, buffer.length))>0) { baos.write(buffer, 0, number); reallyByte=baos.toByteArray(); String info=new String(reallyByte); Message mess=new Message(); mess.obj=info; service.handler.sendMessage(mess); baos.reset(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); sendInfoMessageToUI(sysError); close(); } } // protected void handleTimeout(Selector selector) { // try{ // Iterator iter = selector.keys().iterator(); // while(iter.hasNext()){ // SelectionKey key = iter.next(); // System.out.println("clear:"+key); // // if ( (key.interestOps() & SelectionKey.OP_READ) !=0 ) { // key.cancel(); // key.attach(null); // key.channel().close(); // } // } // }catch(Exception e2){ // e2.printStackTrace(); // } // } // public final String readBuf(InputStream input) // throws IOException { // byte[] buffer=new byte[1024]; // ByteArrayOutputStream baos=new ByteArrayOutputStream(); // int number; // while((number=input.read(buffer, 0, buffer.length))>0) // { // baos.write(buffer, 0, number); // } // byte[] reallyByte=baos.toByteArray(); // String info=new String(reallyByte); // return info; // } protected final boolean writeBuf(byte[] data) throws IOException { if (socket != null && socket.isConnected() &&output!=null&&!socket.isOutputShutdown() && state == running) { output.write(data); output.flush(); return true; } else if (state != running) { return false; } return false; } private void sendInfoMessageToUI(String text) { // TuliaoBaseActivity.sendMessage(ProtocolConst.CMD_SYSTEM_ERROR, text); //// self.setOnline(false); // Iterator keys = all_user.keySet().iterator(); // while (keys.hasNext()) { // UserInfo info = all_user.get(keys.next()); // info.setOnline(false); // } // Message msg = new Message(); // msg.what = ProtocolConst.CMD_HAS_USER_OFFLINE; // msg.obj = all_user; // TuliaoBaseActivity.sendMessage(msg); } /** * 喚起連接線程重新連接 */ protected synchronized void reconnect() { close(); // notify(); } private synchronized void connect() { try { SocketAddress sa=new InetSocketAddress(ProtocolConst.ip,ProtocolConst.port); socket=new Socket(); socket.setSoTimeout(READ_TIMEOUT); socket.setTcpNoDelay(true); // socket.setTrafficClass(0x04 | 0x10); socket.connect(sa, CONNECT_TIMEOUT); output=new DataOutputStream(socket.getOutputStream()); input=new DataInputStream(socket.getInputStream()); if (socket.isConnected()) { // 連接成功開始監聽服務端消息 // 發送一個驗證數據包到服務器進行驗證 state = running; writeBuf("start\n".getBytes("UTF8")); //客戶端接收到start表示心跳的開始 } else { // 關閉通道過30S重新開始連接 sendInfoMessageToUI("服務器連接失敗" + (RECONNECT_TIME / 1000) + "秒後再嘗試連接"); wait(RECONNECT_TIME); reconnect(); } } catch (Exception e) { // TODO Auto-generated catch block // 有異常關閉通道過60S重新開始連接 e.printStackTrace(); sendInfoMessageToUI((RECONNECT_TIME / 1000) + "秒後再嘗試連接"); try { wait(RECONNECT_TIME); reconnect(); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } private void close() { state = connect; try { if (socket != null) { socket.close(); socket = null; } if(input!=null) { input.close(); input=null; } if(output!=null) { output.close(); output=null; } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
public class ProtocolConst { protected static final String ip = "192.168.1.167"; protected static final int port = 4321; }
public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent arg1) { // TODO Auto-generated method stub context.startService(new Intent(context, IMService.class)); } }
8.MainActivity.class:
public class MainActivity extends Activity implements OnClickListener{ /** Called when the activity is first created. */ EditText username; EditText socketAddress; EditText showContent; Button connectButton; Button disconnectButton; Button quitButton; Button sendButton; EditText sendContent; String nameValue; String addressValue; public static final String reconnectTag="reconnect"; SocketAddress address; ReceiverHandler rh; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); username=(EditText)this.findViewById(R.id.username); socketAddress=(EditText)this.findViewById(R.id.serveraddress); showContent=(EditText)this.findViewById(R.id.showcontent); sendContent=(EditText)this.findViewById(R.id.sendcontent); connectButton=(Button)this.findViewById(R.id.connect); disconnectButton=(Button)this.findViewById(R.id.disconnect); quitButton=(Button)this.findViewById(R.id.quit); sendButton=(Button)this.findViewById(R.id.send); sendContent.setOnClickListener(this); connectButton.setOnClickListener(this); disconnectButton.setOnClickListener(this); quitButton.setOnClickListener(this); sendButton.setOnClickListener(this); findViewById(R.id.send_code).setOnClickListener(this); findViewById(R.id.send_close_code).setOnClickListener(this); this.startService(new Intent(this, IMService.class)); } public class ReceiverHandler extends BroadcastReceiver{ Context context=null; public ReceiverHandler(Context context) { this.context=context; } public void registerAction(String action){ IntentFilter filter=new IntentFilter(); filter.addAction(action); context.registerReceiver(this, filter); } @Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equals(IMService.messageTag)) { String message=intent.getStringExtra("message"); Message mess=new Message(); mess.obj=message; handler.sendMessage(mess); } } } public Handler handler= new Handler() { public void handleMessage(Message msg) { String message=msg.obj.toString(); showContent.append(message); } }; @Override protected void onStart() { // TODO Auto-generated method stub super.onStart(); rh=new ReceiverHandler(this); rh.registerAction(IMService.messageTag); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unregisterReceiver(rh); } public static final String FLAG_PLAYER_VIDEO="0"; public static final String FLAG_CREATE_CODE="1"; public static final String FLAG_CLOSE_CODE="2"; public static String createPar(String productId) { String ret=""; JSONObject menu = new JSONObject(); try { menu.put("flag", FLAG_PLAYER_VIDEO); menu.put("msg", "播放商品視頻"); menu.put("productId", productId); ret=menu.toString(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } return ret; } public static String createCodePar(String productId){ String ret=""; JSONObject menu = new JSONObject(); try { menu.put("flag", FLAG_CREATE_CODE); menu.put("msg", "顯示商品二維碼"); menu.put("productId", productId); ret=menu.toString(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } return ret; } public static String closeCodePar(){ String ret=""; JSONObject menu = new JSONObject(); try { menu.put("flag", FLAG_CLOSE_CODE); menu.put("msg", "關閉商品二維碼"); menu.put("productId", null); ret=menu.toString(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } return ret; } public static String getProductID(String str){ String ret=""; if(str!=null&&!str.equals("")){ try { JSONObject obj=new JSONObject(str); ret=obj.getString("productId"); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return ret; } @Override public void onClick(View v) { // TODO Auto-generated method stub String text; switch(v.getId()) { case R.id.send: text=sendContent.getText().toString(); if(text!=null&&!text.equals("")){ text=createPar(text)+"\n"; Log.i("text", text); IMService.addPacket(text); IMService.wakeUp(); sendContent.setText(""); } break; case R.id.send_code: text=sendContent.getText().toString(); if(text!=null&&!text.equals("")){ text=createCodePar(text)+"\n"; Log.i("text", text); IMService.addPacket(text); IMService.wakeUp(); sendContent.setText(""); } break; case R.id.send_close_code: text=closeCodePar()+"\n"; Log.i("text", text); IMService.addPacket(text); IMService.wakeUp(); break; } } }
以上就是我關於Android的Socket通訊客戶端的代碼,下一篇中我會講解服務端的代碼,並與客戶端對接。共勉.
Android Widget開發案例實現是本文要介紹的內容,主要是來了解並學習Android Widget開發應用,今天我們要寫一下Android Widget的開發,由
作為Android四大組件之一,Activity可以說是最基本也是最常見的組件,它提供了一個顯示界面,從而實現與用戶的交互,作為初學者,必須熟練掌握。今天我們就來通過實驗
Fresco簡單的使用—SimpleDraweeView 百學須先立志—學前須知: &n
在SystemUI中有一個Activity可以顯示所有的Logo這個Activity涉及到的圖標存放在SystemUI/res/drawable-nodpi目錄下在這裡我