在downLoadFile中进行网络请求、创建线程池,分配线程下载任务,开启线程下载图片到SD卡,返回下载进程判断变量message.what,判断是否下载完成。
package com.example.tonydandelion.downloadfile;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/** * Created by TonyDandelion on 2015/11/15. */
public class DownLoad {
private Handler handler;
//记得将handler传入到Runnable中,因为是在Runnable中更新UI。
public DownLoad(Handler handler){
this.handler=handler;
}
//建立线程池,一共三个。
private Executor threadPool= Executors.newFixedThreadPool(3);
//给线程池创建Runnable对象,Runnable可以理解为一个任务。
//这个任务只是一个接口。具体的任务执行是在 run()方法执行。
static class DownLoadRunnable implements Runnable{
private Handler handler;
private String url;
private String fileName;
private long start;
private long end;
public DownLoadRunnable(String url,String fileName,long start,long end,Handler handler){
this.url=url;
this.fileName=fileName;
this.start=start;
this.end=end;
this.handler=handler;
}
@Override
public void run() {
//网络访问请求的代码
URL httpUrl = null;
try {
httpUrl = new URL(url);
HttpURLConnection conn=(HttpURLConnection)httpUrl.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
//指定Runnable发送的数据的长度。
conn.setRequestProperty("Range","bytes="+start+"-"+end);
//通过RandomAccessFile往本地文件里面写,方式是可读可写"rwd"
RandomAccessFile access = new RandomAccessFile(new File(fileName),"rwd");
//从start处开始读写
access.seek(start);
//拿到读入流
InputStream in = conn.getInputStream();
//创建一个四字节缓冲区
byte[] b=new byte[1024*4];
int len=0;
//开始读取数据,先往缓冲区里面读数据,只要不为-1,就一直读下去。从0开始读到len的长度。
while((len=in.read(b))!=-1){
access.write(b,0,len);
}
//读取完之后,关掉这个流。
if(access!=null){
access.close();
}
//读完了就关掉读入流 in
if(in!=null){
in.close();
}
//所有文件下载之后想主线程发送一个消息
Message message = new Message();
// message.what设置消息的int值,你可以自己定义。handler里用来区分是哪个消息。
message.what=1;
handler.sendMessage(message);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void downLoadFile(String url){
//网络访问请求的代码
URL httpUrl = null;
try {
httpUrl = new URL(url);
HttpURLConnection conn=(HttpURLConnection)httpUrl.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
//拿到下载图片的整体长度
int count = conn.getContentLength();
//通过三个线程去下载,所以每个线程的长度是整个图片长度的1/3
int block = count/3;
//指定下载的文件的名字,利用getFileName方法,直接从服务器中获取。
String fileName=getFileName(url);
//指定下载的文件的位置,在SD卡中创建这样一个名为fileName的文件。
File parenr= Environment.getExternalStorageDirectory();
File fileDownLoad = new File(parenr,fileName);
//往线程池提交下载任务,开始下载。
/**假设一个文件有11个字节,11/3=3....2 * 第一个线程下载0-2字节 * 第二个线程下载3-5字节 * 第三个线程下载6-10字节 * 最后的两个字节溢出来了当i=2时,说明到了最后一个线程。 * 这时设置 end=count,就能多存溢出的字节。 * */
//开启三个线程
for(int i=0;i<3;i++){
//算出每个线程起始位置和终止位置取数据的区间
long start=i*block;
long end=i*block;
if(i==2){
end=count;
}
//创建Runnable对象
DownLoadRunnable runnable = new DownLoadRunnable(url,fileDownLoad.getAbsolutePath(),start,end,handler);
//通过线程池来提交任务,也就是提交Runnable对象。
threadPool.execute(runnable);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**拿到文件的名字,因为文件的名字在 *url(http://localhost:8080/web/Sky.jpg)最后一个反斜杠的后面 * 所以调用url.substring截取字符串,其中截取的位置是url.lastIndexOf("/")+1 *lastIndexOf("/") 方法可返回指定的字符串("/")值最后出现的位置, * 再加1,就是把Sky.jpg截取了 * */
public String getFileName(String url){
return url.substring(url.lastIndexOf("/")+1);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal">
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下载图片" android:textSize="30sp" android:id="@+id/downloadbutton" android:layout_gravity="center_horizontal"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="36sp" android:id="@+id/textView" />
</LinearLayout>
package com.example.tonydandelion.downloadfile;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.os.Handler;
/** * Created by TonyDandelion on 2015/11/16. */
public class DownLoadActivity extends Activity {
private Button button;
private TextView textView;
private int count = 0;
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg){
int result=msg.what;
count+=result;
//当count等于3的时候,说明下载完成了,打印下载完成到TextView上。
if(count==3){
textView.setText("下载成功!");
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.down);
button= (Button) findViewById(R.id.downloadbutton);
textView= (TextView) findViewById(R.id.textView);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//开新线程来运行DownLoad。Android4.4以上的系统就不允许在主线程里面直接进行网络操作了。
new Thread(){
@Override
public void run() {
DownLoad load = new DownLoad(handler);
load.downLoadFile("http://192.168.1.103:8080/web/Sky.jpg");
}
}.start();
}
});
}
}
点击下载按钮,完成下载。
在文件管理器里面就有Sky.java这个文件了
1、Handler的包,要导import android.os.Handler;这个,不能导import java.util.logging.Handler;这个。
2、因为Android4.4以上的系统就不允许在主线程里面直接访问网络,所以我们要自己新开一个线程来运行DownLoad.java,记得调用这个新开线程的start方法。