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下載完畢後就裏面發出一個事件通知主線程數據下載完畢,並及時的解碼和顯示。後續再改進。