您的位置:首页 > 移动开发 > Android开发

android 多线程断点下载,listview 模式 开始 暂停等功能

2013-10-05 20:19 369 查看
android 多线程断点下载,listview 模式



代码依次如下:

布局:

<?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:id="@+id/llRoot">

     <ListView android:id="@android:id/list"

         android:layout_width="fill_parent"

         android:layout_height="fill_parent">

     </ListView>

 </LinearLayout>

item布局:

<?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="wrap_content">

     <LinearLayout

            android:orientation="horizontal"

            android:layout_width="fill_parent"

            android:layout_height="wrap_content"

            android:layout_marginBottom="5dip">

         <TextView 

             android:layout_width="fill_parent"

             android:layout_height="wrap_content"

             android:layout_weight="1"

             android:id="@+id/tv_resouce_name"/>

         <Button

             android:layout_width="fill_parent"

             android:layout_height="wrap_content"

             android:layout_weight="1"

             android:text="下载"

             android:id="@+id/btn_start"

             android:onClick="startDownload"/>

         <Button

             android:layout_width="fill_parent"

             android:layout_height="wrap_content"

             android:layout_weight="1"

             android:text="暂停"

             android:visibility="gone"

             android:id="@+id/btn_pause"

             android:onClick="pauseDownload"/>

       </LinearLayout>

 </LinearLayout>

代码:

package com.jiaruihuademo.download;

 

 import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import android.app.ListActivity;

import android.os.AsyncTask;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.view.View;

import android.widget.Button;

import android.widget.LinearLayout;

import android.widget.LinearLayout.LayoutParams;

import android.widget.ProgressBar; 

import android.widget.TextView;

import android.widget.Toast;

/**

 * 

 * @author jiaruihua jrhhybh@163.com

 *

 */

 public class MainActivity extends ListActivity { 

     // 固定下载的资源路径,这里可以设置网络上的地址

//     private static final String URL = "http://download.haozip.com/";

     private static final String URL = "http://android.baoruan.com/download/downpage/down/subid/1605853/id/1604353/mid/12874";

     // 固定存放下载文件路径:SD卡目录下

     private static final String SD_PATH = "/mnt/sdcard/";

     // 存放各个下载器

     private Map<String, Download> downloaders = new HashMap<String, Download>();

     // 存放与下载器对应的进度条

     private Map<String, ProgressBar> ProgressBars = new HashMap<String, ProgressBar>();

     /**

      * 利用消息处理机制适时更新进度条

      */

     private Handler mHandler = new Handler() {

         public void handleMessage(Message msg) {

             if (msg.what == 1) {

                 String url = (String) msg.obj;

                 int length = msg.arg1;

                 ProgressBar bar = ProgressBars.get(url);

                 if (bar != null) {

                     // 设置进度条按读取的length长度更新

                     bar.incrementProgressBy(length);

                     if (bar.getProgress() == bar.getMax()) {

                    LinearLayout layout = (LinearLayout) bar.getParent();

                    TextView resouceName=(TextView)layout.findViewById(R.id.tv_resouce_name);

                         Toast.makeText(MainActivity.this, "["+resouceName.getText()+"]下载完成!", Toast.LENGTH_SHORT).show();

                         // 下载完成后清除进度条并将map中的数据清空

                         layout.removeView(bar);

                         ProgressBars.remove(url);

                         downloaders.get(url).delete(url);

                         downloaders.get(url).reset();

                         downloaders.remove(url);

                         

                         Button btn_start=(Button)layout.findViewById(R.id.btn_start);

                         Button btn_pause=(Button)layout.findViewById(R.id.btn_pause);

                         btn_pause.setVisibility(View.GONE);

                         btn_start.setVisibility(View.GONE);

                     }

                 }

             }

         }

     };

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main); 

         showListView();

     }

     // 显示listView,这里可以随便添加

     private void showListView() {

         List<Map<String, String>> data = new ArrayList<Map<String, String>>();

         Map<String, String> map = new HashMap<String, String>();

//         map.put("name", "haozip_v3.1.exe");

//         data.add(map);

//         map = new HashMap<String, String>();

//         map.put("name", "haozip_v3.1_hj.exe");

//         data.add(map);

//         map = new HashMap<String, String>();

//         map.put("name", "haozip_v2.8_x64_tiny.exe");

//         data.add(map);

//         map = new HashMap<String, String>();

//         map.put("name", "haozip_v2.8_tiny.exe");

//         data.add(map);

         map.put("name", "baoruan.com_8133f45539");

         data.add(map);

         DownLoadAdapter adapter=new DownLoadAdapter(this,data);  

         setListAdapter(adapter);

         

     }

     /**

      * 响应开始下载按钮的点击事件

      */

     public void startDownload(View v) {

         // 得到textView的内容 

         LinearLayout layout = (LinearLayout) v.getParent();

         String resouceName = ((TextView) layout.findViewById(R.id.tv_resouce_name)).getText().toString();

         String urlstr = URL + resouceName;

         String localfile = SD_PATH + resouceName;

         //设置下载线程数为4,这里是我为了方便随便固定的

         String threadcount = "4";

         DownloadTask downloadTask=new DownloadTask(v);

         downloadTask.execute(urlstr,localfile,threadcount);

       

     };

    class DownloadTask extends AsyncTask<String, Integer, LoadInfo>{

    Download downloader=null; 

    View v=null;

    String urlstr=null;

    public DownloadTask(final View v){

    this.v=v;

    }  

    @Override

    protected void onPreExecute() { 

    Button btn_start=(Button)((View)v.getParent()).findViewById(R.id.btn_start);

    Button btn_pause=(Button)((View)v.getParent()).findViewById(R.id.btn_pause);

    btn_start.setVisibility(View.GONE);

    btn_pause.setVisibility(View.VISIBLE);

    }
@Override
protected LoadInfo doInBackground(String... params) {
urlstr=params[0];
String localfile=params[1];
int threadcount=Integer.parseInt(params[2]);
// 初始化一个downloader下载器
        downloader = downloaders.get(urlstr);
        if (downloader == null) {
            downloader = new Download(urlstr, localfile, threadcount, MainActivity.this, mHandler);
            downloaders.put(urlstr, downloader);
        }
        if (downloader.isdownloading())
       
return null;
        // 得到下载信息类的个数组成集合
        return downloader.getDownloaderInfors(); 
}
@Override
protected void onPostExecute(LoadInfo loadInfo) {
if(loadInfo!=null){
// 显示进度条
        showProgress(loadInfo, urlstr, v);
        // 调用方法开始下载
        downloader.download();

}
 
};

     /**

      * 显示进度条

      */

     private void showProgress(LoadInfo loadInfo, String url, View v) {

         ProgressBar bar = ProgressBars.get(url);

         if (bar == null) {

             bar = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);

             bar.setMax(loadInfo.getFileSize());

             bar.setProgress(loadInfo.getComplete());

             ProgressBars.put(url, bar);

             LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, 5);

             ((LinearLayout) ((LinearLayout) v.getParent()).getParent()).addView(bar, params);

         }

     }

     /**

      * 响应暂停下载按钮的点击事件

      */

     public void pauseDownload(View v) {

         LinearLayout layout = (LinearLayout) v.getParent();

         String resouceName = ((TextView) layout.findViewById(R.id.tv_resouce_name)).getText().toString();

         String urlstr = URL + resouceName;

         downloaders.get(urlstr).pause();

         Button btn_start=(Button)((View)v.getParent()).findViewById(R.id.btn_start);

  Button btn_pause=(Button)((View)v.getParent()).findViewById(R.id.btn_pause);

         btn_pause.setVisibility(View.GONE);

         btn_start.setVisibility(View.VISIBLE);

     }

 }

下载:

package com.jiaruihuademo.download;

import java.io.File;

import java.io.InputStream;

import java.io.RandomAccessFile;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import android.content.Context;

import android.os.AsyncTask;

import android.os.Handler;

import android.os.Message;

import android.util.Log;

/**

 * 

 * @author jiaruihua jrhhybh@163.com

 *

 */

public class Download {

    private String urlstr;// 下载的地址

    private String localfile;// 保存路径

    private int threadcount;// 线程数

    private Handler mHandler;// 消息处理器 

    private int fileSize;// 所要下载的文件的大小

    private Context context; 

    private List<DownloadInfo> infos;// 存放下载信息类的集合

    private static final int INIT = 1;//定义三种下载的状态:初始化状态,正在下载状态,暂停状态

    private static final int DOWNLOADING = 2;

    private static final int PAUSE = 3;

    private int state = INIT;

    public Download(String urlstr, String localfile, int threadcount,

            Context context, Handler mHandler) {

        this.urlstr = urlstr;

        this.localfile = localfile;

        this.threadcount = threadcount;

        this.mHandler = mHandler;

        this.context = context;

    }

    /**

     *判断是否正在下载 

     */

    public boolean isdownloading() {

        return state == DOWNLOADING;

    }

    /**

     * 得到downloader里的信息

     * 首先进行判断是否是第一次下载,如果是第一次就要进行初始化,并将下载器的信息保存到数据库中

     * 如果不是第一次下载,那就要从数据库中读出之前下载的信息(起始位置,结束为止,文件大小等),并将下载信息返回给下载器

     */

    public LoadInfo getDownloaderInfors() {

        if (isFirst(urlstr)) {

            Log.v("TAG", "isFirst");

            init();

            int range = fileSize / threadcount;

            infos = new ArrayList<DownloadInfo>();

            for (int i = 0; i < threadcount - 1; i++) {

                DownloadInfo info = new DownloadInfo(i, i * range, (i + 1)* range - 1, 0, urlstr);

                infos.add(info);

            }

            DownloadInfo info = new DownloadInfo(threadcount - 1,(threadcount - 1) * range, fileSize - 1, 0, urlstr);

            infos.add(info);

            //保存infos中的数据到数据库

            GetDownloadInfos.getInstance(context).saveInfos(infos);

            //创建一个LoadInfo对象记载下载器的具体信息

            LoadInfo loadInfo = new LoadInfo(fileSize, 0, urlstr);

            return loadInfo;

        } else {

            //得到数据库中已有的urlstr的下载器的具体信息

            infos = GetDownloadInfos.getInstance(context).getInfos(urlstr);

            Log.v("TAG", "not isFirst size=" + infos.size());

            int size = 0;

            int compeleteSize = 0;

            for (DownloadInfo info : infos) {

                compeleteSize += info.getCompeleteSize();

                size += info.getEndPos() - info.getStartPos() + 1;

            }

            return new LoadInfo(size, compeleteSize, urlstr);

        }

    }

    /**

     * 初始化

     */

    private void init() {

        try {

            URL url = new URL(urlstr);

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            connection.setConnectTimeout(5000);

            connection.setRequestMethod("GET");

            fileSize = connection.getContentLength();

            File file = new File(localfile);

            if (!file.exists()) {

                file.createNewFile();

            }

            // 本地访问文件

            RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");

            accessFile.setLength(fileSize);

            accessFile.close();

            connection.disconnect();

        } catch (Exception e) {

            e.printStackTrace();

        }

    }  

    /**

     * 判断是否是第一次 下载

     */

    private boolean isFirst(String urlstr) {

        return GetDownloadInfos.getInstance(context).isHasInfors(urlstr);

    }

    /**

     * 利用线程开始下载数据

     */

    public void download() {

        if (infos != null) {

            if (state == DOWNLOADING)

                return;

            state = DOWNLOADING;

            for (DownloadInfo info : infos) {

                new MyThread(info.getThreadId(), info.getStartPos(),

                        info.getEndPos(), info.getCompeleteSize(),

                        info.getUrl()).start();

            }

        }

    }

    public class MyThread extends Thread {

        private int threadId;

        private int startPos;

        private int endPos;

        private int compeleteSize;

        private String urlstr;

        public MyThread(int threadId, int startPos, int endPos,

                int compeleteSize, String urlstr) {

            this.threadId = threadId;

            this.startPos = startPos;

            this.endPos = endPos;

            this.compeleteSize = compeleteSize;

            this.urlstr = urlstr;

        }

        @Override

        public void run() {

            HttpURLConnection connection = null;

            RandomAccessFile randomAccessFile = null;

            InputStream is = null;

            try {

                URL url = new URL(urlstr);

                connection = (HttpURLConnection) url.openConnection();

                connection.setConnectTimeout(5000);

                connection.setRequestMethod("GET");

                // 设置范围,格式为Range:bytes x-y;

                connection.setRequestProperty("Range", "bytes="+(startPos + compeleteSize) + "-" + endPos);

                randomAccessFile = new RandomAccessFile(localfile, "rwd");

                randomAccessFile.seek(startPos + compeleteSize);

                // 将要下载的文件写到保存在保存路径下的文件中

                is = connection.getInputStream();

                byte[] buffer = new byte[4096];

                int length = -1;

                while ((length = is.read(buffer)) != -1) {

                    randomAccessFile.write(buffer, 0, length);

                    compeleteSize += length;

                    // 更新数据库中的下载信息

                    GetDownloadInfos.getInstance(context).updataInfos(threadId, compeleteSize, urlstr);

                    // 用消息将下载信息传给进度条,对进度条进行更新

                    Message message = Message.obtain();

                    message.what = 1;

                    message.obj = urlstr;

                    message.arg1 = length;

                    mHandler.sendMessage(message);

                    if (state == PAUSE) {

                        return;

                    }

                }

            } catch (Exception e) {

                e.printStackTrace();

            }  

        }

    }

    //删除数据库中urlstr对应的下载器信息

    public void delete(String urlstr) {

    GetDownloadInfos.getInstance(context).delete(urlstr);

    }

    //设置暂停

    public void pause() {

        state = PAUSE;

    }

    //重置下载状态

    public void reset() {

        state = INIT;

    }

}

package com.jiaruihuademo.download;

import java.util.List;

import java.util.Map;

import android.content.Context;

import android.view.LayoutInflater;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.Button;

import android.widget.TextView;

/**

 * 

 * @author jiaruihua jrhhybh@163.com

 * 

 */

public class DownLoadAdapter extends BaseAdapter {

private LayoutInflater mInflater;
private List<Map<String, String>> data;
private Context context;
private OnClickListener click;

public DownLoadAdapter(Context context, List<Map<String, String>> data) {
this.context = context;
mInflater = LayoutInflater.from(context);
this.data = data;
}

public void refresh(List<Map<String, String>> data) {
this.data = data;
this.notifyDataSetChanged();
}

public void setOnclick(OnClickListener click) {
this.click = click;
}

@Override
public int getCount() {
return data.size();
}

@Override
public Object getItem(int position) {
return data.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final Map<String, String> bean = data.get(position);
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.resouceName = (TextView) convertView
.findViewById(R.id.tv_resouce_name);
holder.startDownload = (Button) convertView
.findViewById(R.id.btn_start);
holder.pauseDownload = (Button) convertView
.findViewById(R.id.btn_pause);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.resouceName.setText(bean.get("name"));
return convertView;
}

public OnClickListener getClick() {
return click;
}

public void setClick(OnClickListener click) {
this.click = click;
}

private class ViewHolder {
public TextView resouceName;
public Button startDownload;
public Button pauseDownload;
}

}

package com.jiaruihuademo.download;

/**@author 

 * jiaruihua jrhhybh@163.com

 *创建一个下载信息的实体类

 */

public class DownloadInfo {

    private int threadId;//下载器id

    private int startPos;//开始点

    private int endPos;//结束点

    private int compeleteSize;//完成度

    private String url;//下载器网络标识

    public DownloadInfo(int threadId, int startPos, int endPos,

            int compeleteSize,String url) {

        this.threadId = threadId;

        this.startPos = startPos;

        this.endPos = endPos;

        this.compeleteSize = compeleteSize;

        this.url=url;

    }

    public DownloadInfo() {

    }

    public String getUrl() {

        return url;

    }

    public void setUrl(String url) {

        this.url = url;

    }

    public int getThreadId() {

        return threadId;

    }

    public void setThreadId(int threadId) {

        this.threadId = threadId;

    }

    public int getStartPos() {

        return startPos;

    }

    public void setStartPos(int startPos) {

        this.startPos = startPos;

    }

    public int getEndPos() {

        return endPos;

    }

    public void setEndPos(int endPos) {

        this.endPos = endPos;

    }

    public int getCompeleteSize() {

        return compeleteSize;

    }

    public void setCompeleteSize(int compeleteSize) {

        this.compeleteSize = compeleteSize;

    }

    @Override

    public String toString() {

        return "DownloadInfo [threadId=" + threadId

                + ", startPos=" + startPos + ", endPos=" + endPos

                + ", compeleteSize=" + compeleteSize +"]";

    }

}

package com.jiaruihuademo.download;

import java.util.ArrayList;

import java.util.List;

import android.content.Context;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

/**

 * @author jiaruihua jrhhybh@163.com

 * 一个业务类

 */

public class GetDownloadInfos {  
private static GetDownloadInfos dao=null;
private Context context; 
private  GetDownloadInfos(Context context) { 
this.context=context;
}
public static  GetDownloadInfos getInstance(Context context){
if(dao==null){
dao=new GetDownloadInfos(context); 
}
return dao;
}
public  SQLiteDatabase getConnection() {
SQLiteDatabase sqliteDatabase = null;
try { 
sqliteDatabase= new MyDbHelper(context).getReadableDatabase();
} catch (Exception e) {  
}
return sqliteDatabase;
}

/**
* 查看数据库中是否有数据
*/
public synchronized boolean isHasInfors(String urlstr) {
SQLiteDatabase database = getConnection();
int count = -1;
Cursor cursor = null;
try {
String sql = "select count(*)  from download_info where url=?";
cursor = database.rawQuery(sql, new String[] { urlstr });
if (cursor.moveToFirst()) {
count = cursor.getInt(0);

} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != database) {
database.close();
}
if (null != cursor) {
cursor.close();
}
}
return count == 0;
}

/**
* 保存 下载的具体信息
*/
public synchronized void saveInfos(List<DownloadInfo> infos) {
SQLiteDatabase database = getConnection();
try {
for (DownloadInfo info : infos) {
String sql = "insert into download_info(thread_id,start_pos, end_pos,compelete_size,url) values (?,?,?,?,?)";
Object[] bindArgs = { info.getThreadId(), info.getStartPos(),
info.getEndPos(), info.getCompeleteSize(),
info.getUrl() };
database.execSQL(sql, bindArgs);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != database) {
database.close();
}
}
}

/**
* 得到下载具体信息
*/
public synchronized List<DownloadInfo> getInfos(String urlstr) {
List<DownloadInfo> list = new ArrayList<DownloadInfo>();
SQLiteDatabase database = getConnection();
Cursor cursor = null;
try {
String sql = "select thread_id, start_pos, end_pos,compelete_size,url from download_info where url=?";
cursor = database.rawQuery(sql, new String[] { urlstr });
while (cursor.moveToNext()) {
DownloadInfo info = new DownloadInfo(cursor.getInt(0),
cursor.getInt(1), cursor.getInt(2), cursor.getInt(3),
cursor.getString(4));
list.add(info);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != database) {
database.close();
}
if (null != cursor) {
cursor.close();
}
}
return list;
}

/**
* 更新数据库中的下载信息
*/
public synchronized void updataInfos(int threadId, int compeleteSize, String urlstr) {
SQLiteDatabase database = getConnection();
try {
String sql = "update download_info set compelete_size=? where thread_id=? and url=?";
Object[] bindArgs = { compeleteSize, threadId, urlstr };
database.execSQL(sql, bindArgs);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != database) {
database.close();
}
}
}

/**
* 下载完成后删除数据库中的数据
*/
public synchronized void delete(String url) {
SQLiteDatabase database = getConnection();
try {
database.delete("download_info", "url=?", new String[] { url });
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != database) {
database.close();
}
}
}

}

package com.jiaruihuademo.download;

/**

 * @author jiaruihua jrhhybh@163.com

 *  自定义的一个记载下载器详细信息的类

 */

public class LoadInfo {
public int fileSize;// 文件大小
private int complete;// 完成度
private String urlstring;// 下载器标识

public LoadInfo(int fileSize, int complete, String urlstring) {
this.fileSize = fileSize;
this.complete = complete;
this.urlstring = urlstring;
}

public LoadInfo() {
}

public int getFileSize() {
return fileSize;
}

public void setFileSize(int fileSize) {
this.fileSize = fileSize;
}

public int getComplete() {
return complete;
}

public void setComplete(int complete) {
this.complete = complete;
}

public String getUrlstring() {
return urlstring;
}

public void setUrlstring(String urlstring) {
this.urlstring = urlstring;
}

@Override
public String toString() {
return "LoadInfo [fileSize=" + fileSize + ", complete=" + complete
+ ", urlstring=" + urlstring + "]";
}

}

package com.jiaruihuademo.download;

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

/**

 * @author jiaruihua jrhhybh@163.com

 *  建立一个数据库帮助类

 */

public class MyDbHelper extends SQLiteOpenHelper {
// download.db-->数据库名
public MyDbHelper(Context context) {
super(context, "download.db", null, 1);
}

/**
* 在download.db数据库下创建一个download_info表存储下载信息
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table download_info(_id integer PRIMARY KEY AUTOINCREMENT, thread_id integer, "
+ "start_pos integer, end_pos integer, compelete_size integer,url char)");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

}

权限:

<uses-permission android:name="android.permission.INTERNET" />

   

    

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息