GreenDao+多線程和斷點續傳實現下載

先看下效果圖:

點擊下載進度條開始動,實現下載



點擊下載後下載按鈕變成不可按的狀態

暫停按鈕變成可按狀態


點擊暫停後下載按鈕再次變成可按狀態,點擊下載繼續續傳


下載完成後,下載完成按鈕變成可點擊,


下載完成後點擊下載完成播放下載的視頻


下面開始粘代碼:

首先我們生成GreenDao

首先我們需要在項目build.gradle中導入包`

    dependencies {     
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1'
    }


在model倒入依賴:

compile 'org.greenrobot:greendao:3.2.0'
compile 'org.greenrobot:greendao-generator:3.2.0'

接着在模塊build.gradle的頂部添加 apply plugin: ‘org.greenrobot.greendao’ 以及

  greendao {
        schemaVersion 1
        daoPackage 'com.xxxxx.xxx'//這個是生成代碼保存的包名
        targetGenDir 'src/main/java'//保存到java代碼路徑
    }
同步後就可以使用greenDao。

生成bean

@Entity
public class User {
    @Id
    private Long id;
    private Integer thread_id;
    private Integer start_pos;
    private Integer end_pos;
    private Integer compelete_size;
    private String url;
	//下面的都是自動生成
    @Generated(hash = 2041931179)
    public User(Long id, Integer thread_id, Integer start_pos, Integer end_pos,
            Integer compelete_size, String url) {
        this.id = id;
        this.thread_id = thread_id;
        this.start_pos = start_pos;
        this.end_pos = end_pos;
        this.compelete_size = compelete_size;
        this.url = url;
    }
    @Generated(hash = 586692638)
    public User() {
    }
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public Integer getThread_id() {
        return this.thread_id;
    }
    public void setThread_id(Integer thread_id) {
        this.thread_id = thread_id;
    }
    public Integer getStart_pos() {
        return this.start_pos;
    }
    public void setStart_pos(Integer start_pos) {
        this.start_pos = start_pos;
    }
    public Integer getEnd_pos() {
        return this.end_pos;
    }
    public void setEnd_pos(Integer end_pos) {
        this.end_pos = end_pos;
    }
    public Integer getCompelete_size() {
        return this.compelete_size;
    }
    public void setCompelete_size(Integer compelete_size) {
        this.compelete_size = compelete_size;
    }
    public String getUrl() {
        return this.url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    
}

自動生成是點擊build

就能自動的生成你需要的Dao類和helper類


那麼使用之前需要初始化一下

public class App extends Application{
    public static UserDao userDao;

    @Override
    public void onCreate() {
        super.onCreate();
        DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(this, "lenvess.db", null);
        DaoMaster daoMaster = new DaoMaster(devOpenHelper.getWritableDb());
        DaoSession daoSession = daoMaster.newSession();
        userDao = daoSession.getUserDao();

    }
}

GreenDao註解:

@Entity 用於標識這是一個需要Greendao幫我們生成代碼的bean

@Id 標明主鍵,括號裏可以指定是否自增

@Property 用於設置屬性在數據庫中的列名(默認不寫就是保持一致)

@NotNull 非空

@Transient 標識這個字段是自定義的不會創建到數據庫表裏

@Unique 添加唯一約束

@ToOne 是將自己的一個屬性與另一個表建立關聯(外鍵)


@ToMany的屬性referencedJoinProperty,類似於外鍵約束。


@JoinProperty 對於更復雜的關係,可以使用這個註解標明目標屬性的源屬性。


------------------------------------------------------------------------------------------------下面說下載的----------------------------------------------------------------------------------------------------------------------

public class DownlaodSqlTool {
    /**
     * 創建下載的具體信息
     */
    public void insertInfos(List<DownloadInfo> infos) {
        for (DownloadInfo info : infos) {
            User user = new User(null, info.getThreadId(), info.getStartPos(), info.getEndPos(), info.getCompeleteSize(), info.getUrl());
            userDao.insert(user);
        }
    }

    /**
     * 得到下載具體信息
     */
    public List<DownloadInfo> getInfos(String urlstr) {
        List<DownloadInfo> list = new ArrayList<DownloadInfo>();
        List<User> list1 = userDao.queryBuilder().where(UserDao.Properties.Url.eq(urlstr)).build().list();
        for (User user : list1) {
            DownloadInfo infoss = new DownloadInfo(
                    user.getThread_id(), user.getStart_pos(), user.getEnd_pos(),
                    user.getCompelete_size(), user.getUrl());
            Log.d("main-----", infoss.toString());
            list.add(infoss);
        }

        return list;
    }

    /**
     * 更新數據庫中的下載信息
     */
    public void updataInfos(int threadId, int compeleteSize, String urlstr) {
        User user = userDao.queryBuilder()
                .where(UserDao.Properties.Thread_id.eq(threadId), UserDao.Properties.Url.eq(urlstr)).build().unique();
        user.setCompelete_size(compeleteSize);
        userDao.update(user);
    }

    /**
     * 下載完成後刪除數據庫中的數據
     */
    public void delete(String url) {
        userDao.deleteAll();
    }


}

public class DownloadHttpTool {
    /**
     * 利用Http協議進行多線程下載具體實踐類
     */

    private static final String TAG = DownloadHttpTool.class.getSimpleName();
    private int threadCount;//線程數量
    private String urlstr;//URL地址
    private Context mContext;
    private Handler mHandler;
    private List<DownloadInfo> downloadInfos;//保存下載信息的類

    private String localPath;//目錄
    private String fileName;//文件名
    private int fileSize;
    private DownlaodSqlTool sqlTool;//文件信息保存的數據庫操作類

    private enum Download_State {
        Downloading, Pause, Ready;//利用枚舉表示下載的三種狀態
    }

    private Download_State state = Download_State.Ready;//當前下載狀態

    private int globalCompelete = 0;//所有線程下載的總數

    public DownloadHttpTool(int threadCount, String urlString,
                            String localPath, String fileName, Context context, Handler handler) {
        super();
        this.threadCount = threadCount;
        this.urlstr = urlString;
        this.localPath = localPath;
        this.mContext = context;
        this.mHandler = handler;
        this.fileName = fileName;
        sqlTool = new DownlaodSqlTool();
    }

    //在開始下載之前需要調用ready方法進行配置
    public void ready() {
        Log.w(TAG, "ready");
        globalCompelete = 0;
        downloadInfos = sqlTool.getInfos(urlstr);
        if (downloadInfos.size() == 0) {
            initFirst();
        } else {
            File file = new File(localPath + "/" + fileName);
            if (!file.exists()) {
                sqlTool.delete(urlstr);
                initFirst();
            } else {
                fileSize = downloadInfos.get(downloadInfos.size() - 1)
                        .getEndPos();
                for (DownloadInfo info : downloadInfos) {
                    globalCompelete += info.getCompeleteSize();
                }
                Log.w(TAG, "globalCompelete:::" + globalCompelete);
            }
        }
    }

    public void start() {
        Log.w(TAG, "start");
        if (downloadInfos != null) {
            if (state == Download_State.Downloading) {
                return;
            }
            state = Download_State.Downloading;
            for (DownloadInfo info : downloadInfos) {
                Log.v(TAG, "startThread");
                new DownloadThread(info.getThreadId(), info.getStartPos(),
                        info.getEndPos(), info.getCompeleteSize(),
                        info.getUrl()).start();
            }
        }
    }

    public void pause() {
        state = Download_State.Pause;
    }

    public void delete() {
        compelete();
        File file = new File(localPath + "/" + fileName);
        file.delete();
    }

    public void compelete() {
        sqlTool.delete(urlstr);
    }
    //加載完成
    public void loadEnd(){
        Toast.makeText(mContext,"加載完成",Toast.LENGTH_SHORT).show();
    }

    public int getFileSize() {
        return fileSize;
    }

    public int getCompeleteSize() {
        return globalCompelete;
    }

    //第一次下載初始化
    private void initFirst() {
        Log.w(TAG, "initFirst");
        try {
            URL url = new URL(urlstr);
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();
            connection.setConnectTimeout(5000);
            connection.setRequestMethod("GET");
            fileSize = connection.getContentLength();
            Log.w(TAG, "fileSize::" + fileSize);
            File fileParent = new File(localPath);
            if (!fileParent.exists()) {
                fileParent.mkdir();
            }
            File file = new File(fileParent, fileName);
            if (!file.exists()) {
                file.createNewFile();
            }
            // 本地訪問文件
            RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
            accessFile.setLength(fileSize);
            accessFile.close();
            connection.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        int range = fileSize / threadCount;
        downloadInfos = new ArrayList<DownloadInfo>();
        for (int i = 0; i < threadCount - 1; i++) {
            DownloadInfo info = new DownloadInfo(i, i * range, (i + 1) * range
                    - 1, 0, urlstr);
            downloadInfos.add(info);
        }
        DownloadInfo info = new DownloadInfo(threadCount - 1, (threadCount - 1)
                * range, fileSize - 1, 0, urlstr);
        downloadInfos.add(info);
        sqlTool.insertInfos(downloadInfos);
    }

    //自定義下載線程
    private class DownloadThread extends Thread {

        private int threadId;
        private int startPos;
        private int endPos;
        private int compeleteSize;
        private String urlstr;
        private int totalThreadSize;

        public DownloadThread(int threadId, int startPos, int endPos,
                              int compeleteSize, String urlstr) {
            this.threadId = threadId;
            this.startPos = startPos;
            this.endPos = endPos;
            totalThreadSize = endPos - startPos + 1;
            this.urlstr = urlstr;
            this.compeleteSize = compeleteSize;
        }

        @Override
        public void run() {
            HttpURLConnection connection = null;
            RandomAccessFile randomAccessFile = null;
            InputStream is = null;
            try {
                randomAccessFile = new RandomAccessFile(localPath + "/"
                        + fileName, "rwd");
                randomAccessFile.seek(startPos + compeleteSize);
                URL url = new URL(urlstr);
                connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(5000);
                connection.setRequestMethod("GET");
                connection.setRequestProperty("Range", "bytes="
                        + (startPos + compeleteSize) + "-" + endPos);
                is = connection.getInputStream();
                byte[] buffer = new byte[1024];
                int length = -1;
                while ((length = is.read(buffer)) != -1) {
                    randomAccessFile.write(buffer, 0, length);
                    compeleteSize += length;
                    Message message = Message.obtain();
                    message.what = threadId;
                    message.obj = urlstr;
                    message.arg1 = length;
                    mHandler.sendMessage(message);
                    sqlTool.updataInfos(threadId, compeleteSize, urlstr);
                    Log.w(TAG, "Threadid::" + threadId + "    compelete::"
                            + compeleteSize + "    total::" + totalThreadSize);
                    if (compeleteSize >= totalThreadSize) {
                        break;
                    }
                    if (state != Download_State.Downloading) {
                        break;
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (is != null) {
                        is.close();
                    }
                    randomAccessFile.close();
                    connection.disconnect();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

}


public class DownloadInfo {
    /**
     * 保存每個下載線程下載信息類
     *
     */

    private int threadId;// 下載器id
    private int startPos;// 開始點
    private int endPos;// 結束點
    private int compeleteSize;// 完成度
    private String url;// 下載文件的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
                + "]";
    }



}

public class DownloadUtil {
    private DownloadHttpTool mDownloadHttpTool;
    private OnDownloadListener onDownloadListener;

    private int fileSize;
    private int downloadedSize = 0;

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            int length = msg.arg1;
            synchronized (this) {//加鎖保證已下載的正確性
                downloadedSize += length;
            }
            if (onDownloadListener != null) {
                onDownloadListener.downloadProgress(downloadedSize);
            }
            if (downloadedSize >= fileSize) {
                mDownloadHttpTool.compelete();
                if (onDownloadListener != null) {
                    onDownloadListener.downloadEnd();
                }
            }
        }

    };

    public DownloadUtil(int threadCount, String filePath, String filename,
                        String urlString, Context context) {

        mDownloadHttpTool = new DownloadHttpTool(threadCount, urlString,
                filePath, filename, context, mHandler);
    }

    //下載之前首先異步線程調用ready方法獲得文件大小信息,之後調用開始方法
    public void start() {
        new AsyncTask<Void,Void,Void>() {

            @Override
            protected Void doInBackground(Void... arg0) {
                // TODO Auto-generated method stub
                mDownloadHttpTool.ready();
                return null;
            }

            @Override
            protected void onPostExecute(Void result) {
                // TODO Auto-generated method stub
                super.onPostExecute(result);
                fileSize = mDownloadHttpTool.getFileSize();
                downloadedSize = mDownloadHttpTool.getCompeleteSize();
                Log.w("Tag", "downloadedSize::" + downloadedSize);
                if (onDownloadListener != null) {
                    onDownloadListener.downloadStart(fileSize);
                }
                mDownloadHttpTool.start();
            }
        }.execute();
    }

    public void pause() {
        mDownloadHttpTool.pause();
    }

    public void delete(){
        mDownloadHttpTool.delete();
    }
    public void loadend(){
        mDownloadHttpTool.loadEnd();
    }

    public void reset(){
        mDownloadHttpTool.delete();
        start();
    }

    public void setOnDownloadListener(OnDownloadListener onDownloadListener) {
        this.onDownloadListener = onDownloadListener;
    }

    //下載回調接口
    public interface OnDownloadListener {
        public void downloadStart(int fileSize);

        public void downloadProgress(int downloadedSize);//記錄當前所有線程下總和

        public void downloadEnd();
    }

}


activity使用

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    @BindView(R.id.start)
    Button start;
    @BindView(R.id.delete)
    Button pause;
    @BindView(R.id.loadAll)
    Button loadAll;
    @BindView(R.id.progressBar)
    ProgressBar mProgressBar;
    @BindView(R.id.textView)
    TextView total;
    @BindView(R.id.videoview)
    VideoView videoview;
    
    private int max;
    private DownloadUtil mDownloadUtil;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        total.setText("加載:0%");
        

        String urlString = "http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4";
        String localPath = Environment.getExternalStorageDirectory()
                .getAbsolutePath() + "/local";
        mDownloadUtil = new DownloadUtil(4, localPath, "adc.mp4", urlString,
                this);
        mDownloadUtil.setOnDownloadListener(new DownloadUtil.OnDownloadListener() {

            @Override
            public void downloadStart(int fileSize) {
                // TODO Auto-generated method stub
                Log.w(TAG, "fileSize::" + fileSize);
                max = fileSize;
                mProgressBar.setMax(fileSize);
              
            }

            @Override
            public void downloadProgress(int downloadedSize) {
                // TODO Auto-generated method stub
                Log.w(TAG, "Compelete::" + downloadedSize);
                mProgressBar.setProgress(downloadedSize);

               

                //textView進度
                total.setText((long) downloadedSize * 100 / mProgressBar.getMax() + "%");
                
            }

            @Override
            public void downloadEnd() {
                // TODO Auto-generated method stub
                Log.w(TAG, "ENd");
                loadAll.setEnabled(true);
                total.setText("加載完成");
            }
        });

        start.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                //開始
                start.setEnabled(false);
                pause.setEnabled(true);
                loadAll.setEnabled(false);
                mDownloadUtil.start();


            }
        });
        pause.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                //按鈕可點擊狀態
                start.setEnabled(true);
                pause.setEnabled(true);
                //暫停
                mDownloadUtil.pause();



            }
        });

        loadAll.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                mDownloadUtil.loadend();
                //獲取sd卡目錄adc.map4文件
                File file = new File(Environment.getExternalStorageDirectory(), "/local/adc.mp4");
                //判斷目錄文件是否存在
                if (file.exists()) {
                    //視頻播放路徑
                    videoview.setVideoPath(file.getPath());
                    if (!videoview.isPlaying()) {
                        //開始播放
                        videoview.start();
                    }

                } else {
                    Toast.makeText(MainActivity.this, "文件不存在", Toast.LENGTH_SHORT).show();

                }
            }
        });


    }
}


最後佈局也粘出來

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.bwie.wudan20180115.MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:orientation="horizontal"
        >
        <Button
            android:id="@+id/start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下載" />
        <Button
            android:id="@+id/delete"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:enabled="false"
            android:text="暫停" />
        <Button
            android:id="@+id/loadAll"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:enabled="false"
            android:text="下載完成" />
    </LinearLayout>

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="7.5dp"
        android:layout_marginRight="8dp"
        android:layout_marginLeft="8dp"
        android:max="100"
        android:progress="100"
        android:visibility="visible" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="8dp"
        android:text="TextView" />

    

    <VideoView
        android:id="@+id/videoview"
        android:layout_marginTop="30dp"
        android:layout_width="match_parent"
        android:layout_height="200dp" />


</LinearLayout>













發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章