Android之網絡下載與圖片解碼-----網絡圖片瀏覽器

1.Android系統網絡,與其他系統一樣,主要分低級別的socket編程和基於協議的http編程。當然http編程也是基於socket編程的。由於tcp/IP 協議棧是一致的,所以各個平臺網絡編程流程和思想是一樣的,只是接口不同而已。

2.android的媒體庫已經完成了圖片,音視頻解碼,圖片解碼主要是BitmapFactory庫來完成,解碼處理的位圖在再imageView進行展示即可

3.由於網絡涉及到用戶的隱私權限,所以必須在清單文件中註冊

<uses-permission android:name="android.permission.INTERNET" />  

3.Android 3.0 以後,不允許在主線程中下載,必需開啓一個子線程來完成網絡下載動作,如果硬要在主線程完成網絡下載,必須在代碼中申請權限。

在開發中,爲了防止訪問網絡阻塞主線程,一般都要把訪問網絡放在獨立線程中或者異步線程AsyncTask中。但是由於某些原因,想要忽略這些強制策略問題的話,可以在onCreate()方法裏面加上
StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
就可以解決該問題。另外在類的前面,要加上@SuppressLint("NewApi")才行。


清單文件如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.httpdowload"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
   <uses-permission android:name="android.permission.INTERNET" />  
  

    <application
        android:allowBackup="true"
        android:icon="@drawable/show"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        
        <activity
            android:screenOrientation="portrait"
            android:name="com.example.httpdowload.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

所用的字符串

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">HttpShow</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
      <string name="url">請輸入網址</string>
       <string name="show">圖片顯示</string>
</resources>

佈局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
     android:background="#808080"
    >
    <TextView 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/url"
        android:textSize="15sp"
        android:textColor="#ffffff"
       
        />
    <EditText
        android:layout_width="fill_parent"
        android:layout_height="30sp"
        android:inputType="textUri"
        android:background="#000000"
        android:layout_margin="4sp"
        android:id="@+id/edittext"
        android:textColor="#ffffff"
        
       
        />
      <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/show"
        android:textSize="15sp"
        android:textColor="#ffffff"
         android:id="@+id/button"
       
        />
    <ImageView 
          android:id="@+id/image"  
          android:scaleType="centerCrop"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
          android:maxWidth="500sp"
          android:maxHeight="750sp"
          android:contentDescription="@string/show"
         android:src="@drawable/bg"
         android:background="#00fa9a"
       />
    </LinearLayout >

主activity代碼如下:

package com.example.httpdowload;

import com.example.httpservice.httpservice;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.StrictMode;


public class MainActivity extends ActionBarActivity {

	private EditText text;
	private Button button;
	private ImageView image;
	private String path;
	
	@SuppressLint("NewApi")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		text=(EditText)this.findViewById(R.id.edittext);
		button=(Button)this.findViewById(R.id.button);
		image=(ImageView) this.findViewById(R.id.image);
		button.setOnClickListener(listener);
		StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();
		StrictMode.setThreadPolicy(policy);
	}
	private OnClickListener listener =new OnClickListener() 
	{

		@Override
		public void onClick(View v) {
			Button bx=(Button) v;
			switch(bx.getId())
			{
			case R.id.button :
				  			path=text.getText().toString();
				  			try {
				  				   Log.i("mytag","network connetct is begin!");
				  					byte[]Data = httpservice.download(path);
				  					Bitmap  bitmap=BitmapFactory.decodeByteArray(Data, 0, Data.length);
				  					image.setImageBitmap(bitmap);
				  				}
				  			catch (Exception e)
				  			{
				  				Log.e("mytag","Error is happen!");
				  				e.printStackTrace();
				  			}
				  			break;
				default:
							break;
			}
			
		}
		
	};
	

}

網絡下載代碼如下:

package com.example.httpservice;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.util.Log;

public class httpservice {
public static  byte[] download(String path) throws Exception
{

	URL url=new URL(path);
	Log.i("mynet",path);
	HttpURLConnection conn=(HttpURLConnection)url.openConnection();
	conn.setConnectTimeout(5000);
	conn.setRequestMethod("GET");
	conn.setReadTimeout(5000);
	Log.i("mynet","wait for the response!");
	 Log.e("mynet","code="+conn.getResponseCode());
   if(conn.getResponseCode()==200)
   {
	   Log.i("mynet","netwok is connect success!");
	   InputStream inStream=conn.getInputStream();
	   return DataGet.read(inStream);
   }
   else
   {
	   Log.e("mynet","network is connetct failed"+"code"+conn.getResponseCode());
   }
	return null;
}
}
網路讀數據代碼如下:

package com.example.httpservice;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import android.util.Log;

public class DataGet {
	public static byte[] read(InputStream inStream) throws Exception{
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = 0;
		int count =0;
		while( (len = inStream.read(buffer)) != -1){
			outStream.write(buffer, 0, len);
			count++;
		}
		Log.i("data","data is read finish"+count);
		inStream.close();
		return outStream.toByteArray();
}
}
效果如下:




以上代碼將網絡下載,與ACtivity放在一個線程中,如果圖片很大會影響效率。這裏創建一個子線程專門用來網絡下載。

package com.example.httpdowload;

import com.example.httpservice.httpservice;

import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.StrictMode;


public class MainActivity extends ActionBarActivity {

	private EditText text;
	private Button button;
	private ImageView image;
	private String path;
	byte[]Data;
	Bitmap  bitmap;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		text=(EditText)this.findViewById(R.id.edittext);
		button=(Button)this.findViewById(R.id.button);
		image=(ImageView) this.findViewById(R.id.image);
		button.setOnClickListener(listener);
	/*	StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();
		StrictMode.setThreadPolicy(policy);  如果讓下載代碼在主線程中跑,需要在系統中申請該權限,因爲
		Android 3.0 以後,不允許在主線程中下載,必需開啓一個子線程來完成網絡下載動作*/
	}
	private OnClickListener listener =new OnClickListener() 
	{

		@Override
		public void onClick(View v) {
			Button bx=(Button) v;
			switch(bx.getId())
			{
			case R.id.button :
				  			path=text.getText().toString();
				  			try {
				  				   Log.i("mytag","network connetct is begin thread!");
				  					/*byte[]Data = httpservice.download(path);*/
				  				 Thread t =new Thread(new Runnable() 
				  				 {   
				  				   public void run() { 
				  					 
				  					 try {
										Data = httpservice.download(path);
										bitmap=BitmapFactory.decodeByteArray(Data, 0, Data.length);
										
										
									} catch (Exception e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
				  					 
				  					               }   
				  				});   
				  				t.start(); 
				  				Thread.sleep(3000);
				  				image.setImageBitmap(bitmap);
				  				
				  			}
				  			catch (Exception e)
				  			{
				  				Log.e("mytag","Error is happen!");
				  				e.printStackTrace();
				  			}
				  			break;
				default:
							break;
			}
			
		}
		
	};
	
	
}

該方法還存在無問題,也就是線程下載完圖片數據後,如何及時通知主線程解碼呢?因爲主線程也不能查詢下載完畢的狀態,從而達到下載和解碼的同步,這裏暫且用2s 延時來等等下載完畢,但有時網絡不好,3s延時也不夠用。造成第一次點擊button後,沒圖片顯示,必需第二次後才顯示。

以上通過延時方法來同步會影響體驗性,無法達成下載和解碼準確同步。

規範的做法應該是創建一個service來下載,在service創建一個線程做下載,而後主線程訂閱這個事件,這樣service下載完畢後就裏面發出一個事件通知主線程數據下載完畢,並及時的解碼和顯示。後續再改進。



發佈了71 篇原創文章 · 獲贊 22 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章