天天看點

斷點背景下載下傳

首先看效果圖:

斷點背景下載下傳
斷點背景下載下傳
實作思路:使用HttpURLConnection和AsyncTask(便于及時取消任務,實作暫停下載下傳的功能)實作斷點下載下傳,将下載下傳進度儲存到資料庫中,每次打開程式時周遊資料庫,設定進度調的初始狀态。

資料庫操作:

DownloadContract類,包含表名,字段名
public class DownloadContract {
    // 為了防止有人意外地執行個體化合同類,使構造函數私有。
    private DownloadContract() {
    }

    /* 内部類定義表的内容 */
    public static class DownloadEntry implements BaseColumns {
        public static final String TABLE_NAME = "downloadentry";
        public static final String COLUMN_NAME_TID = "tid";
        public static final String COLUMN_NAME_JINDU = "jindu";
        public static final String COLUMN_NAME_YIXIAZAI = "yixiazai";
        public static final String COLUMN_NAME_PATH = "path";
    }
}
           
SQLTool類,包含建立,删除表的語句
public class SQLTool {
    private  static final String TEXT_TYPE = " TEXT";
    private static final String INTEGER_TYPE = " INTEGER";
    private static final String COMMA_SEP = ",";
    public static final String SQL_CREATE_ENTRIES =
            "CREATE TABLE " + DownloadContract.DownloadEntry.TABLE_NAME + " (" +
                    DownloadContract.DownloadEntry._ID + " INTEGER PRIMARY KEY," +
                    DownloadContract.DownloadEntry.COLUMN_NAME_TID + INTEGER_TYPE + COMMA_SEP +
                    DownloadContract.DownloadEntry.COLUMN_NAME_JINDU + INTEGER_TYPE + COMMA_SEP +
                    DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI + INTEGER_TYPE +COMMA_SEP +
                    DownloadContract.DownloadEntry.COLUMN_NAME_PATH + TEXT_TYPE + " )";

    public static final String SQL_DELETE_ENTRIES =
            "DROP TABLE IF EXISTS " + DownloadContract.DownloadEntry.TABLE_NAME;
}
           
DownloadDbHelper類,繼承SQLiteOpenHelper
public class DownloadDbHelper extends SQLiteOpenHelper {
    // 如果更改資料庫模式,則必須增加資料庫版本。
    public static final int DATABASE_VERSION = ;
    public static final String DATABASE_NAME = "dl.db";

    public DownloadDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(SQL_CREATE_ENTRIES);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        // 這個資料庫隻是一個用于線上資料的緩存,是以其更新政策是簡單地丢棄資料并重新開始
        sqLiteDatabase.execSQL(SQL_DELETE_ENTRIES);
        onCreate(sqLiteDatabase);
    }

    @Override
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        onUpgrade(db, oldVersion, newVersion);
    }
}
           
DAOHelper類,包含增删改查操作
public class DAOHelper {

    private DownloadDbHelper downloadDbHelper;

    public DAOHelper(Context context) {
        downloadDbHelper = new DownloadDbHelper(context);
    }

    public long add(Download download) {
        // 以寫入模式擷取資料存儲庫
        SQLiteDatabase db = downloadDbHelper.getWritableDatabase();

        //建立一個新的值映射,其中列名稱是鍵
        ContentValues values = new ContentValues();

        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_TID, download.gettId());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_JINDU, download.getJindu());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI, download.getYixiazai());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_PATH, download.getPath());
        // 插入新行,傳回新行的主鍵值,-表示插入失敗
        long newRowId = db.insert(DownloadContract.DownloadEntry.TABLE_NAME, null, values);
        return newRowId;
    }

    public void delete(int tID) {
        SQLiteDatabase db = downloadDbHelper.getWritableDatabase();
        // 定義查詢的“where”部分。
        String selection = DownloadContract.DownloadEntry.COLUMN_NAME_TID + " LIKE ?";
        // 在占位符順序中指定參數。
        String[] selectionArgs = {tID + ""};
        // 發出SQL語句。
        db.delete(DownloadContract.DownloadEntry.TABLE_NAME, selection, selectionArgs);
    }

    public int update(Download download) {
        SQLiteDatabase db = downloadDbHelper.getReadableDatabase();

        ContentValues values = new ContentValues();
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_JINDU, download.getJindu());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI, download.getYixiazai());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_PATH, download.getPath());

        // 要更新的行
        String selection = DownloadContract.DownloadEntry.COLUMN_NAME_TID + " LIKE ?";
        String[] selectionArgs = {download.gettId() + ""};
        // 得到受影響的行數
        int count = db.update(
                DownloadContract.DownloadEntry.TABLE_NAME,
                values,
                selection,
                selectionArgs);
        return count;
    }

    public boolean select(int tID) {
        SQLiteDatabase db = downloadDbHelper.getReadableDatabase();

        String[] projection = {
                DownloadContract.DownloadEntry.COLUMN_NAME_TID,
                DownloadContract.DownloadEntry.COLUMN_NAME_JINDU,
                DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI,
                DownloadContract.DownloadEntry.COLUMN_NAME_PATH
        };

        String selection = DownloadContract.DownloadEntry.COLUMN_NAME_TID + " = ?";
        String[] selectionArgs = {tID + ""};

        String sortOrder =
                DownloadContract.DownloadEntry.COLUMN_NAME_TID + " DESC";

        Cursor c = db.query(
                DownloadContract.DownloadEntry.TABLE_NAME,
                projection,
                selection,
                selectionArgs,
                null,
                null,
                sortOrder
        );

        if (c.moveToFirst()) {
            return true;
        } else {
            return false;
        }
    }

    public List<Download> selectAll() {

        List<Download> dataList = new ArrayList<Download>();
        SQLiteDatabase db = downloadDbHelper.getReadableDatabase();

        Cursor c = db.query(
                DownloadContract.DownloadEntry.TABLE_NAME,
                null,
                null,
                null,
                null,
                null,
                null
        );
        while (c.moveToNext()) {
            Log.d("dl", "添加");
            Download download = new Download();
            download.settId(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_TID)));
            download.setJindu(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_JINDU)));
            download.setYixiazai(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI)));
            download.setPath(c.getString(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_PATH)));
            dataList.add(download);
        }
        return dataList;
    }

}
           
Download實體類
public class Download {

    private int tId;
    private int jindu;
    private int yixiazai;
    private String path;

    public int gettId() {
        return tId;
    }

    public void settId(int tId) {
        this.tId = tId;
    }

    public int getJindu() {
        return jindu;
    }

    public void setJindu(int jindu) {
        this.jindu = jindu;
    }

    public int getYixiazai() {
        return yixiazai;
    }

    public void setYixiazai(int yixiazai) {
        this.yixiazai = yixiazai;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    @Override
    public String toString() {
        return "Download{" +
                "tId=" + tId +
                ", jindu=" + jindu +
                ", yixiazai=" + yixiazai +
                ", path='" + path + '\'' +
                '}';
    }
}
           

Service

DownloadSerivce類
public class DownloadSerivce extends Service {
    private int jindu;
    private File dlFile, file;
    private DownloadTask downloadTask;
    private long alreadySize;
    private Timer timer;
    private DAOHelper daoHelper;


    private final IBinder mBinder = new DLBinder();


    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case :
                    NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
                    builder.setSmallIcon(R.mipmap.ic_launcher);
                    builder.setContentTitle("自定義點選事件");
                    RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.remoteview);
                    remoteViews.setProgressBar(R.id.progressBar, , jindu, false);
                    remoteViews.setTextViewText(R.id.textView, jindu + "%");

                    builder.setContent(remoteViews);
                    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                    startForeground(, builder.build());
                    break;
            }
        }
    };

    public class DLBinder extends Binder {
        public DownloadSerivce getService() {
            return DownloadSerivce.this;
        }
    }

    @Override
    public void onCreate() {
        daoHelper = new DAOHelper(this);

        file = getTemporaryStorageDir(getApplicationContext(), "apk");
        Log.d("dl", "path = " + file.getAbsolutePath());

        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setContentTitle("自定義點選事件");
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.remoteview);
        remoteViews.setProgressBar(R.id.progressBar, , jindu, false);
        remoteViews.setTextViewText(R.id.textView, jindu + "%");

        builder.setContent(remoteViews);
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        startForeground(, builder.build());

        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    // 開始下載下傳
    public void startDL(int tID) {
        if (downloadTask == null) {
            downloadTask = new DownloadSerivce.DownloadTask();
            downloadTask.execute("http://msoftdl.360.cn/mobilesafe/shouji360/360safe/6002520/360MobileSafe.apk");
            if (timer != null) {
                timer.cancel();
            }
            timer = new Timer();
            timer.schedule(new TimerTask() {
                public void run() {
                    Message msg = new Message();
                    msg.what = ;
                    handler.sendMessage(msg);
                }
            }, , );
        }
    }

    // 暫停下載下傳
    public void pauseDL(int tID) {
        if (downloadTask != null) {
            downloadTask.cancel(true);
            downloadTask = null;
        }

        if (timer != null) {
            timer.cancel();
        }


        Download download = new Download();
        download.settId();
        download.setJindu(jindu);
        download.setYixiazai((int) alreadySize);
        download.setPath(file.getAbsolutePath() + "/360.apk");
        int i = daoHelper.update(download);
        Log.d("dl", "updateline = " + i);

        List<Download> list = new ArrayList<Download>();
        list = daoHelper.selectAll();

        Log.d("dl", "list = " + list.toString());
    }

    public File getTemporaryStorageDir(Context context, String albumName) {
        // 擷取臨時檔案夾
        dlFile = new File(context.getExternalFilesDir(
                Environment.DIRECTORY_DOWNLOADS), albumName);
        if (dlFile.mkdirs() || dlFile.isDirectory()) {
            Log.d("dl", "檔案夾已存在");
        } else {
            Log.d("dl", "檔案夾建立失敗");
        }
        return dlFile;
    }

    // 擷取下載下傳進度
    public int getJindu(int tID) {
        Log.d("dl", "jindu = " + jindu);
        return jindu;
    }

    public class DownloadTask extends AsyncTask<String, Integer, String> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected String doInBackground(String... strings) {
            try {

                //建立URL對象
                URL url = new URL(strings[]);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                //已經下載下傳的位元組數
                alreadySize = ;
                //将檔案寫到指定目錄中
                File file = new File(dlFile.getAbsolutePath(), "123.apk");
                if (file.exists()) {
                    //如果檔案存在,就擷取目前檔案的大小
                    alreadySize = file.length();
                }

                conn.addRequestProperty("range", "bytes=" + alreadySize + "-");
                conn.connect();
                // 獲得傳回結果
                int code = conn.getResponseCode();
                // 響應成功傳回206
                if (code == ) {
                    // 擷取未下載下傳的檔案的大小
                    long unfinishedSize = conn.getContentLength();
                    // 檔案的大小
                    long size = alreadySize + unfinishedSize;
                    Log.d("dl", "size = " + size);
                    // 擷取輸入流
                    InputStream in = conn.getInputStream();
                    // 擷取輸出對象,在原檔案後追加
                    OutputStream out = new BufferedOutputStream(new FileOutputStream(file, true));

                    // 開始下載下傳
                    byte[] buff = new byte[];
                    int len;
                    StringBuilder sb = new StringBuilder();
                    while ((len = in.read(buff)) != -) {
                        out.write(buff, , len);
                        // 累加已下載下傳的大小
                        alreadySize += len;
                        // 更新進度
                        publishProgress((int) (alreadySize *  / size * ));
                    }
                    out.close();
                } else {
                    Toast.makeText(DownloadSerivce.this, "下載下傳失敗", Toast.LENGTH_SHORT).show();
                }
                conn.disconnect();
            } catch (Exception e) {
                e.printStackTrace();
            }

            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            jindu = (values[]);
        }
    }
}
           

以上是準備工作。

下面是具體的使用代碼:

布局檔案

remoteview.xml
<?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="50dp"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="0.9" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="0.1" />

</LinearLayout>
           
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.jqk.backgrounddownload.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <ProgressBar
            android:id="@+id/progressBar1"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.7"
            android:max="100" />

        <TextView
            android:id="@+id/jindu"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.1" />

        <Button
            android:id="@+id/start"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.1"
            android:text="開始" />

        <Button
            android:id="@+id/pause"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.1"
            android:text="暫停" />
    </LinearLayout>
</LinearLayout>
           

Activity

MainActivity.java
public class MainActivity extends AppCompatActivity {

    private Button start, pause;
    private ProgressBar progressBar;
    private File dlFile, file;
    private TextView tvJindu;
    private List<Download> all;
    private DAOHelper daoHelper;
    private DownloadSerivce mService;
    private boolean mBound = false;
    // 定時任務,更新下載下傳進度
    private Timer timer;

    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            DownloadSerivce.DLBinder binder = (DownloadSerivce.DLBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case :
                    int jindu = mService.getJindu();
                    setData(jindu);
                    break;
            }
        }
    };

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

        start = (Button) findViewById(R.id.start);
        pause = (Button) findViewById(R.id.pause);
        progressBar = (ProgressBar) findViewById(R.id.progressBar1);
        tvJindu = (TextView) findViewById(R.id.jindu);

        file = getTemporaryStorageDir(getApplicationContext(), "apk");
        Log.d("dl", "path = " + file.getAbsolutePath());

        daoHelper = new DAOHelper(this);

        if (!daoHelper.select()) {
            Download download = new Download();
            download.settId();
            download.setJindu();
            download.setYixiazai();
            download.setPath(file.getAbsolutePath() + "/123.apk");
            long i = daoHelper.add(download);
            if (i != -) {
                Toast.makeText(this, "插入成功", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "插入失敗", Toast.LENGTH_SHORT).show();
            }
        } else {
            Toast.makeText(this, "資料已存在", Toast.LENGTH_SHORT).show();
        }

        initData();
        // 啟動服務
        Intent intent = new Intent(this, DownloadSerivce.class);
        startService(intent);
        // 綁定服務
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mService.startDL();
                timer = new Timer();
                timer.schedule(new TimerTask() {
                    public void run() {
                        Message msg = new Message();
                        msg.what = ;
                        handler.sendMessage(msg);
                    }
                }, , );
            }
        });

        pause.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mService.pauseDL();
                if (timer != null) {
                    timer.cancel();
                }
            }
        });
    }

    public void initData() {
        all = new ArrayList<Download>();
        all = daoHelper.selectAll();
        Download download = all.get();
        tvJindu.setText(download.getJindu() + "%");
        progressBar.setProgress(download.getJindu());
    }

    public void setData(int jindu) {
        if (jindu != ) {
            tvJindu.setText(jindu + "%");
            progressBar.setProgress(jindu);
        }
    }

    public File getTemporaryStorageDir(Context context, String albumName) {

        dlFile = new File(context.getExternalFilesDir(
                Environment.DIRECTORY_DOWNLOADS), albumName);
        if (dlFile.mkdirs() || dlFile.isDirectory()) {
            Log.d("dl", "檔案夾已存在");
        } else {
            Log.d("dl", "檔案夾建立失敗");
        }
        return dlFile;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
        Intent intent = new Intent(this, DownloadSerivce.class);
        stopService(intent);
    }
}
           

最後别忘了添權重限,聲明Service

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