/**** 在配置文件中加入如下权限 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); }
}