/**** 在配置文件中加入如下權限 A:訪問網絡的權限 B.C:能夠對SD操做的權限 ***/ <uses-permission android:name="android.permission.INTERNET"/>// <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>java
/**主類?/ package com.example.downloadandprogressor;android
import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast;網絡
public class MainActivity extends Activity {多線程
/*** * 這個Activity操做是把網絡資源下載到 * 本地的SD卡中去 * 咱們採用的是多線程技術進行操做下載 * 因爲手機的硬件資源有限--最好是開啓的線程5條如下爲好 * 本操做也有進度條進行顯示 * 這裏要注意的問題是:耗時的操做必須在子線程中操做--其實 * 這裏的操做最好由Service後臺操做纔好 * 問題2:更新UI組件必需要在主線程中進行 * 不然是不會有效果的 * */ private Handler myhandler =null; private EditText url=null; private Button down = null; private Button exit=null; private TextView sm=null; private ProgressBar progrressbar=null; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //獲取各個組件 url=(EditText)findViewById(R.id.urlE); down=(Button)findViewById(R.id.down); exit=(Button)findViewById(R.id.tcxz);//退出按鈕 sm=(TextView)findViewById(R.id.jd); progrressbar=(ProgressBar)findViewById(R.id.progressbar); myhandler = new MyHander();//這裏負責子線程和主線程的交互--更新UI down.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { String path=url.getText().toString(); startLoad(path,3); } }); exit.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { System.exit(0); } }); } protected void startLoad(String path, int i) { try { DownLoadService.load(path,i,this.progrressbar,this.myhandler); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_main, menu); return true; } private final class MyHander extends Handler{ /*** * 因爲更新UI要在主線程進行 * 又由於在子線程要有數據要返回給主線程 * 因此就要進行Handler操做 * 才能提供一個主線程和子線程交互的平臺 * */ public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); if(msg.what==1){ int size=msg.getData().getInt("size"); progrressbar.setProgress(size);//設置當前的值 if(progrressbar.getProgress()== progrressbar.getMax()){ Toast.makeText(getApplicationContext(), "下載完成", Toast.LENGTH_LONG).show(); sm.setText("100%"); }else{ float v = (float)progrressbar.getProgress() / (float)progrressbar.getMax(); int k = (int)(v*100); sm.setText(k+"%"); } } } }
} /*負責下載的類service?/ package com.example.downloadandprogressor;app
import java.io.File; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL;dom
import android.os.Environment; import android.os.Handler; import android.widget.ProgressBar;ide
public class DownLoadService {this
public static void load(String path, int i,ProgressBar progrressbar,Handler myhandler) throws Exception{ URL url = new URL(path); HttpURLConnection con = (HttpURLConnection)url.openConnection(); con.setReadTimeout(5000); con.setRequestMethod("GET"); //獲取網絡資源的長度 int len = con.getContentLength(); //獲取SD卡路徑 String sdpath=DownLoadService.getSDpath(); if(sdpath==null){ System.out.println("-------------沒有SD卡-------------------"); return; } //建立一個本地的文件--並和其網絡的資源大小同樣 File file = new File(sdpath,DownLoadService.getContentName(path)); RandomAccessFile af = new RandomAccessFile(file, "rwd"); //設置其文件的大小 af.setLength(len); //計算每一個線程要下載的區域 int block = (len%i) == 0 ? len/i : len/i+1; //爲進度條設置最大的值 progrressbar.setMax(len); //開始開啓子線程進行下載 for(int j=0;j<i;j++){ new DownLoadThread(j,file,url,block,myhandler).start(); } } private static String getContentName(String path) { return path.substring(path.lastIndexOf("/")+1); } private static String getSDpath() { String SDpath=null; if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ SDpath=Environment.getExternalStorageDirectory().getPath(); } return SDpath; }
} /**負責下載的線程類?*/ package com.example.downloadandprogressor;url
import java.io.File; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL;.net
import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.Toast;
public class DownLoadThread extends Thread {
public static int size=0; private int j;//線程的ID private File file;//本地文件 private URL url;//網絡資源路徑 private int block;//下載的塊 private Handler myhandler;//負責和線程進行交互 public DownLoadThread(int j, File file, URL url, int block,Handler myhandler) { this.j=j; this.file=file; this.url=url; this.block=block; this.myhandler=myhandler; } public void run() { try{ HttpURLConnection con = (HttpURLConnection)url.openConnection(); con.setReadTimeout(5000); con.setRequestMethod("GET"); //計算開始點和結束點 int start = (j*block); int end = (j+1)*block-1; RandomAccessFile af = new RandomAccessFile(file,"rwd"); af.seek(start);//尋找寫入的位置 //設置請求的頭文件--因爲是多線程下載--因此要設置區域下載大小的頭文件bytes=1-11 con.setRequestProperty("Range", "bytes="+start+"-"+end); //根據返回的狀態嘛判斷是否成功 if(con.getResponseCode() == 206 ){//下載連接成功的狀態嗎爲 206 InputStream in = con.getInputStream(); byte[] buf = new byte[1024]; int len=0; while((len=in.read(buf))!=-1){ //計算目前總的下載量 DownLoadThread.getSize(len,this.myhandler); af.write(buf,0,len); } af.close(); in.close(); System.out.println("第"+j+"線程完成下載"); }else{ System.out.println("第"+j+"線程沒法完成下載"); } }catch(Exception e){ e.printStackTrace(); } } private synchronized static void getSize(int len,Handler myhandler) { DownLoadThread.size+=len; Message msg = new Message(); Bundle b = new Bundle(); b.putInt("size", DownLoadThread.size); msg.setData(b); msg.what=1; myhandler.sendMessage(msg); }
}