使用URLConnection
URLConnection是一個讀取或寫入的網址的連接,使用URLConnection之前必須連接到遠程資源配置。實例URLConnection是不可重用的:你必須使用一個不同的實例爲每個連接到資源。創建一個URLConnection實例,一般只需要new()出一個URL對象,並傳入目標網址,然後調用一下openConnection()方法即可,如下:
URL url=new URL("http://www.360.com");
URLConnection connection=url.openConnection();
之後在調用connection的getInputStream()方法就可以得到服務器返回的輸入流了,(前提是服務器爲運行狀態)接着就對輸入流進行讀取。讀取完成後要記得將輸入流關掉,如下:
InputStream is=connection.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String line=br.readLine();
StringBuffer buffer=new StringBuffer();
while(line!=null){
buffer.append(line);
line=br.readLine();
}
Message msg = handler.obtainMessage();
msg.what=URL_CONENT;
msg.obj=buffer.toString().trim();
handler.sendMessage(msg);
br.close();
is.close();
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="網絡連接內容"/>
<Button
android:id="@+id/btn_network"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="連接網絡"/>
<TextView
android:id="@+id/text_connection"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btn_network;
private Button btn;
private TextView textView_connection;
private static final int URL_CONENT=0x23;
//在這裏對UI進行更新,將結果顯示到界面上
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case URL_CONENT:
String s= (String) msg.obj;
textView_connection.setText(s);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_network= (Button) findViewById(R.id.btn_network);
textView_connection= (TextView) findViewById(R.id.text_connection);
btn_network.setOnClickListener(this);
btn= (Button) findViewById(R.id.button);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_network:
//開啓線程對UI界面進行更新,將結果顯示到界面上
new Thread(new Runnable() {
@Override
public void run() {
connectServerlet();
}
}).start();
break;
case R.id.button:
Intent intent=new Intent(MainActivity.this,NetworkActivity.class);
startActivity(intent);
}
}
private void connectServerlet() {
try {
URL url=new URL("http://192.168.0.82:8080/MyServersTest");
// URL url=new URL("http://www.360.com");
URLConnection connection=url.openConnection();
InputStream is=connection.getInputStream();
//下面對獲取到的輸入流進行讀取
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String line=br.readLine();
StringBuffer buffer=new StringBuffer();
while(line!=null){
buffer.append(line);
line=br.readLine();
}
//將讀取到的結果存放到Message中
Message msg = handler.obtainMessage();
msg.what=URL_CONENT;
msg.obj=buffer.toString().trim();
handler.sendMessage(msg);
br.close();
is.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
要訪問網絡還要開啓權限,在AndroidManifest.xml中:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
下載
單線程下載
需要利用AsyncTask來執行下載任務,要重寫AsyncTask的四個方法
public class DownloadActivity extends Activity implements View.OnClickListener{
private Button btn_single_downlaod;
private Button btn_more_download;
private ProgressBar mDownloadProgressbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
mDownloadProgressbar= (ProgressBar) findViewById(R.id.progress_download);
btn_single_downlaod= (Button) findViewById(R.id.single_download);
btn_single_downlaod.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.single_download:
SingleDownloadTask task=new SingleDownloadTask();
//調用execute()方法啓用SingleDownloadTask任務
task.execute();
break;
}
}
class SingleDownloadTask extends AsyncTask<String,Integer ,String>{
@Override
protected void onPreExecute() {
super.onPreExecute();
mDownloadProgressbar.setVisibility(View.VISIBLE);
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//在這裏更新下載速度
mDownloadProgressbar.setProgress((int) (values[0]*100.0/values[1]));
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//在這裏提示下載結果
btn_single_downlaod.setText("下載完成!");
}
@Override
protected String doInBackground(String... params) {
//執行具體的下載任務
try {
// URL url=new URL("http://192.168.0.30:8080/MyWebTest/music/aa.mp3");
URL url=new URL("http://192.168.0.82:8080/MyServersTest/Music/rainbow.mp3");
URLConnection connection=url.openConnection();
//connection.getContentLength()方法返回響應頭字段指定的字節的內容長度
int length=connection.getContentLength();
// publishProgress(length);
//讀取輸入流的內容
InputStream is=connection.getInputStream();
File file=new File (Environment.getExternalStorageDirectory(),"rainbow.mp3");
if (!file.exists()){
file.createNewFile();
}
//將讀取的內容寫入文件
FileOutputStream os=new FileOutputStream(file);
byte[] array=new byte[1024];
int sum=0;
int index=is.read(array);
while(index!=-1){
os.write(array,0,index);
sum=+index;
//調用publishProgress(Progress...)來更新任務的進度
publishProgress(sum,length);
index=is.read(array);
}
os.flush();
os.close();
is.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
}
服務器端的待下載文件
下載過程
下載到模擬器裏的文件
多線程下載
多線程下載就是將一個文件分爲幾分,交給相應的線程進行處理,由文件長度和分數得到每個線程應該處理的問件長度和開始、結尾處理的部分,最後按照線程的順序將每個線程的文件拼接起來。在最後面的餓結尾處不是都能很好的分配完,所以要特殊處理最後一小段。其他部分基本和單線程一致。這裏的多線程需要一個自定義的線程來處理被分割的各個文件。
activity_download.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progress_download"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/single_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="單線程下載"
/>
<Button
android:id="@+id/multi_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="多線程下載"
/>
</LinearLayout>
</LinearLayout>
MultiThread.java
public class MultiThread extends Thread{
public MultiThread(long start, long end, String url, String filePath) {
this.start = start;
this.end = end;
this.urlPath = url;
this.filePath = filePath;
}
private int sum=0;
private long start;
private long end;
private String urlPath;
private String filePath;
public int getSum() {
return sum;
}
@Override
public void run() {
try {
URL url=new URL(urlPath);
//URL的openConnection()返回這個網址所指的資源的新連接。
URLConnection connection=url.openConnection();
//設置允許用戶交互。
connection.setAllowUserInteraction(true);
//設置指定的請求頭字段的值。價值只能被當前的URLConnection實例使用。這種方法只能在建立連接之前調用。
//第一個參數是設置請求與的頭值 第二個參數指定屬性的新值
connection.setRequestProperty("Range", "bytes=" + start + "-"
+ end);
//讀取輸入流的內容
InputStream is= connection.getInputStream();
byte [] array=new byte[1024];
is.read(array);
File file=new File(filePath);
//RandomAccessFile允許在隨機訪問方式中讀取和寫入文件。這是不同於單向順序訪問一個輸入或輸出提供。
// 如果在讀/寫模式下打開文件,則可使用寫操作。在每次操作之後,可以向前和向後移動讀寫操作的位置。
//RandomAccessFile(file,"rw")構建了一個基於文件的RandomAccessFile實例,根據模式訪問字符串打開它。
RandomAccessFile randomAccessFileile=new RandomAccessFile(file,"rw");
//RandomAccessFile的seek()方法將該文件的文件指針移到一個新的位置,從下面的讀、寫或跳過操作來完成
randomAccessFileile.seek(start);
int index=is.read(array);
while (index!=-1){
//RandomAccessFile的write()方法寫bytecount字節從字節數組緩衝區這個文件,
// 當前文件指針開始使用byteoffset作爲第一位在緩衝區獲取字節。
randomAccessFileile.write(array,0,index);
sum+=index;
index=is.read(array);
}
randomAccessFileile.close();
is.close();
Log.d("此次長度",""+(end-start));
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
DownloadActivity.java
private void MultiDownloadTask() {
new Thread(new Runnable() {
@Override
public void run() {
try {
String urlPath="http://192.168.0.82:8080/MyServersTest/Picture/imagebac.jpg";
URL url=new URL(urlPath);
//URL的openConnection()返回這個網址所指的資源的新連接。
URLConnection connection=url.openConnection();
//connection.getContentLength()方法返回響應頭字段指定的字節的內容長度
length = connection.getContentLength();
Log.d("下載文件的長度",""+length);
//Environment.getExternalStorageDirectory()將文件下載的位置,"image.jpg"下載文件的名字
File file=new File(Environment.getExternalStorageDirectory(),"image.jpg");
//判斷文件是否存在,不存在,則新建文件
if (!file.exists()){
file.createNewFile();
}
//創建線程數組
MultiThread[] threads =new MultiThread[5];
//給線程數組賦值
for (int i=0;i<5;i++){
MultiThread thread=null;
//將最後一個線程和其他線程區分開來
if (i==4){
//最後一個線程處理的長度到文件末尾
thread=new MultiThread(length / 5*4, length , urlPath, file.getAbsolutePath());
Log.d("完成情況","最後看階段段完成"+thread.getSum());
}else {
//非末尾線程處理的長度爲文件總程度/總線程個數
thread=new MultiThread(length / 5 * i, length / 5 * (i + 1)-1, urlPath, file.getAbsolutePath());
Log.d("完成情況","第"+i+"段完成"+thread.getSum());
}
//啓動線程
thread.start();
//給線程數組賦值
threads[i]=thread;
}
//將各個線程的文件拼接起來
boolean isFinish=true;
while(isFinish){
int sum=0;
for (MultiThread thread:threads){
sum+= thread.getSum();
Log.d("文件長度",""+sum+"本次完成"+thread.getSum());
}
//將處理文件長度返回給主線程,對UI進行更新
Message msg= handler.obtainMessage();
msg.what=0x23;
msg.arg1=sum;
handler.sendMessage(msg);
if(sum+10>= length){
isFinish=false;
}
Thread.sleep(1000);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
這裏將多線程下載提成一個方法,最後在多線程下載的按鈕點擊事件裏實現。其結果和單線程一樣。