從服務器 (PC 端 ) 發送圖片到客戶端 (android 手機端 ) ,並在手機頁面上顯示該圖片。(注:本文旨在實現功能,並未考慮效率,有待后續跟進。)
1、服務器端
- int port=9090;
- /**
- * 發送文件的方法
- * 此處定義服務器端口為9090,ip地址為192.168.1.1
- * 設定被傳輸圖片的路徑為"images/icon.png"
- * images文件夾放在此工程的根目錄下,我們就可以通過相對路徑訪問這個圖片文件了
- */
- private void sendPic() {
- try {
- // 創建服務器
- java.net.ServerSocket ss = new java.net.ServerSocket(port);
- // 等待客戶機接入,此處會阻塞,直到有客戶機接入服務器
- java.net.Socket client = ss.accept();
- //創建將要被發送的圖片的文件輸入流
- java.io.FileInputStream fin = new java.io.FileInputStream("images/icon.png");
- //獲得套接字的輸出流,並包裝成數據輸出流
- java.io.DataOutputStream dou = new java.io.DataOutputStream(client
- .getOutputStream());
- // 向輸出流中寫入文件數據長度
- dou.writeInt(fin.available());//注:此處未考慮圖片太大超出int范圍,以至於出現內存溢出的情況
- // 將實際的圖片數據讀取到byte[] data中
- byte[] data = new byte[fin.available()];
- fin.read(data);
- // 將圖片數據寫入到輸出流中
- dou.write(data);
- dou.flush();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
2 、 客戶端(android手機)
- public class FrontPage extends android.app.Activity implements Runnable {
- public void onCreate(android.os.Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.frontpage);
- // 啟動讀取套接字中數據並進行處理的線程
- new Thread(this).start();// 本類繼承了Runnable接口,所以創建線程時將本類的對象傳入即可
- }
- String ip = "192.168.1.1";
- int port = 9090;
- android.widget.ImageView image;// 用於顯示接收到的圖片的ImageView對象
- /**
- * 由於輸入流的read方法會阻塞,為了避免它影響主界面的其他數據處理, 啟動一個線程來讀取輸入流中的數據,並對數據進行相應的處理
- */
- public void run() {
- try {
- // 創建與服務器的連結
- java.net.Socket sc = new java.net.Socket(ip, port);
- // 獲得界面顯示圖片的ImageView對象
- image = (android.widget.ImageView) findViewById(R.id.image);
- // 獲得套接字的輸入流並包裝成基本數據輸入流
- java.io.DataInputStream din = new java.io.DataInputStream(sc
- .getInputStream());
- // 不斷監聽輸入流的數據情況
- while (true) {
- // 當流中有數據時,讀取數據並進行處理
- if (din.available() > 0) {
- // 創建data數組並將流中數據讀取到數組中
- byte[] data = new byte[din.readInt()];// 注此處同樣沒有處理圖片大小超過int的范圍的情況
- din.read(data);
- // 根據讀到的文件數據創建Bitmap對象bitmap,因為將要在后面的內部類中使用bitmap,所以定義為
- // final型
- final android.graphics.Bitmap bitmap = android.graphics.BitmapFactory
- .decodeByteArray(data, 0, data.length);
- // 將圖片顯示到ImageView上
- // 此處由於view中的組件都是線程不安全的,使用android提供的這個辦法處理(詳見下文“附2”)
- image.post(new Runnable() {
- public void run() {
- // 將bitmap顯示到界面上
- image.setImageBitmap(bitmap);
- }
- });
- }
- // 線程休息1s
- Thread.sleep(1000);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
3、main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- xmlns:android1="http://schemas.android.com/apk/res/android"
- xmlns:android="http://schemas.android.com/apk/res/android">
- <ImageView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/image"
- android:gravity="center" />
- </LinearLayout>
附1 、android做通信時需要在AndroidMainFest中添加一個permission:
- <uses-permission android:name="android.permission.INTERNET"></uses-permission>
附2 、關於android中view的組件線程不安全,已經有很多前輩對此做了詳盡的分析,在此我就不再贅述,只給大家提供一個可供參考的地址:http://www.cnblogs.com/playing/archive/2011/03/24/1993583.html
附3 、發送和接收數據時,有很多種方法可選,此處使用的byte數組方法有幾點需要注意:
a、new byte[]時,傳入的數組大小是int型的,所以我們必須考慮到當文件數據超出整型的范圍時,需要輔以別的方法來保證數據的完整性。
b、從文件讀取數據,並寫入到輸出流時,文中使用的代碼是:
- byte[] data = new byte[fin.available()];//創建用於存放文件數據數組
- fin.read(data);//將文件數據讀取到數組中
- dou.write(data);// 將數組寫入到輸出流中
可是不乏有偷懶的碼友這樣寫:
- dou.write(fin.read(new byte[fin.available()]));
- //只要我們稍微查看一下JDK就會發現:read()如果因為已經到達文件末尾而沒有更多的數據,則返回 <code>-1,這樣一來寫入到輸出流中的可就不是我們的文件數據了哦!</code>
更有甚者會這樣寫:
- dou.write(new byte[fin.available()]);//根本就沒有將文件數據讀入到數組中
以上幾種錯誤都是我自己遇到過的,這類很細節的問題要檢查出來都會比較費時間,希望各位碼友引以為戒!
