Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android技術精髓-BackupActivity

Android技術精髓-BackupActivity

編輯:關於Android編程

Android技術精髓-BackupActivity
首先介紹下今天主題BackupActivity功能:在Android應用UI activity 中繼承AsynTask 異步開啟後台線程,實現數據庫動態備份(backup)、恢復的功能(restore) 可方便的使我們的Android程序在onPause()暫停中備份數據庫文件,在Onresume()恢復中恢復數據庫。 vc7EvP607c7zCgo8YnI+CgoKcHVibGljIHN0YXRpYyBmaW5hbCBpbnQgQkFDS1VQX1NVQ0NFU1MgPSAxOwpwdWJsaWMgc3RhdGljIGZpbmFsIGludCBSRVNUT1JFX1NVQ0NFU1MgPSAyOwpwdWJsaWMgc3RhdGljIGZpbmFsIGludCBCQUNLVVBfRVJST1IgPSAzOwpwdWJsaWMgc3RhdGljIGZpbmFsIGludCBSRVNUT1JFX05PRklMRUVSUk9SID0gNDsKPGJyPgoK0tS8sLao0uXBvbj2w/zB7qO6IMr9vt2/4rG4t93D/MHuoaLK/b7dv+K71ri0w/zB7go8YnI+CgoKcHVibGljIHN0YXRpYyBmaW5hbCBTdHJpbmcgQ09NTUFORF9CQUNLVVAgPSA="backupDatabase"; public static final String COMMAND_RESTORE = "restoreDatabase";
設計外用listener接口CompletionListener,方便後續擴展完成後操作
public interface CompletionListener { void onBackupComplete();
void onRestoreComplete();
void onError(int errorCode); }
AsynTask的核心在於doInBackground()中後台運行我們備份以及恢復的工作,
當task後台收到 COMMAND_BACKUP 開始備份備份數據庫 收到COMMAND_RESTORE 開始恢復數據庫
if (command.equals(COMMAND_BACKUP)) { try { //執行備份 } catch (IOException e) { return BACKUP_ERROR; } } else if (command.equals(COMMAND_RESTORE)) { try { //執行恢復 } catch (IOException e) { return BACKUP_ERROR; } } else { return BACKUP_ERROR; }
因此我們動態的在UI activity 中使用task.execute()去執行我們定義好的命令COMMAND就可動態,在onpause()中使用備份,onresume()中使用恢復數據庫。
請看代碼:
package activitys;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

import android.app.Activity;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.widget.Toast;

class BackupTask extends AsyncTask {

	public interface CompletionListener {
		void onBackupComplete();

		void onRestoreComplete();

		void onError(int errorCode);
	}

	public static final int BACKUP_SUCCESS = 1;
	public static final int RESTORE_SUCCESS = 2;
	public static final int BACKUP_ERROR = 3;
	public static final int RESTORE_NOFILEERROR = 4;

	public static final String COMMAND_BACKUP = "backupDatabase";
	public static final String COMMAND_RESTORE = "restoreDatabase";

	private Context mContext;
	private CompletionListener listener;

	public BackupTask(Context context) {
		super();
		mContext = context;
	}

	public void setCompletionListener(CompletionListener aListener) {
		listener = aListener;
	}

	@Override
	protected Integer doInBackground(String... params) {
		File dbFile = mContext.getDatabasePath("mydb");
		File exportDir = new File(Environment.getExternalStorageDirectory(),
				"myAppBackups");
		if (!exportDir.exists()) {
			exportDir.mkdirs();
		}
		File backup = new File(exportDir, dbFile.getName());
		String command = params[0];
		if (command.equals(COMMAND_BACKUP)) {
			try {
				backup.createNewFile();
				fileCopy(dbFile, backup);
				return BACKUP_SUCCESS;
			} catch (IOException e) {
				return BACKUP_ERROR;
			}
		} else if (command.equals(COMMAND_RESTORE)) {
			try {
				if (!backup.exists()) {
					return RESTORE_NOFILEERROR;
				}
				dbFile.createNewFile();
				fileCopy(backup, dbFile);
				return RESTORE_SUCCESS;
			} catch (IOException e) {
				return BACKUP_ERROR;
			}
		} else {
			return BACKUP_ERROR;
		}
	}

	@Override
	protected void onPostExecute(Integer result) {

		switch (result) {
		case BACKUP_SUCCESS:
			if (listener != null) {
				listener.onBackupComplete();
			}
			break;
		case RESTORE_SUCCESS:
			if (listener != null) {
				listener.onRestoreComplete();
			}
			break;
		case RESTORE_NOFILEERROR:
			if (listener != null) {
				listener.onError(RESTORE_NOFILEERROR);
			}
			break;
		default:
			if (listener != null) {
				listener.onError(BACKUP_ERROR);
			}
		}
	}

	private void fileCopy(File source, File dest) throws IOException {
		FileChannel inChannel = new FileInputStream(source).getChannel();
		FileChannel outChannel = new FileOutputStream(dest).getChannel();
		try {
			inChannel.transferTo(0, inChannel.size(), outChannel);
		} finally {
			if (inChannel != null)
				inChannel.close();
			if (outChannel != null)
				outChannel.close();
		}
	}
}



接下來在BackupActivity 我們調用接口BackupTask,實現後台線程,分別在onpause()、onresume()執行task命令進行相應備份、恢復操作如下: @Override public void onResume() { super.onResume(); if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { BackupTask task = new BackupTask(this); task.setCompletionListener(this); task.execute(BackupTask.COMMAND_RESTORE); } }
@Override public void onPause() { super.onPause(); if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { BackupTask task = new BackupTask(this); task.execute(BackupTask.COMMAND_BACKUP); } }


請看代碼:
package activitys;

import com.example.design_activitys.R;

import android.app.Activity;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.Environment;
import android.widget.Toast;

public class BackupActivity extends Activity implements BackupTask.CompletionListener {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		SQLiteDatabase db = openOrCreateDatabase("mydb", Activity.MODE_PRIVATE,
				null);
		db.close();
	}

	@Override
	public void onResume() {
		super.onResume();
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			BackupTask task = new BackupTask(this);
			task.setCompletionListener(this);
			task.execute(BackupTask.COMMAND_RESTORE);
		}
	}

	@Override
	public void onPause() {
		super.onPause();
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			BackupTask task = new BackupTask(this);
			task.execute(BackupTask.COMMAND_BACKUP);
		}
	}

	@Override
	public void onBackupComplete() {
		Toast.makeText(this, "Backup Successful", Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onError(int errorCode) {
		if (errorCode == BackupTask.RESTORE_NOFILEERROR) {
			Toast.makeText(this, "No Backup to Restore", Toast.LENGTH_SHORT)
					.show();
		} else {
			Toast.makeText(this, "Error: " + errorCode, Toast.LENGTH_SHORT)
					.show();
		}
	}

	@Override
	public void onRestoreComplete() {
		Toast.makeText(this, "Restore Successful", Toast.LENGTH_SHORT).show();
	}
}




AsyncTask用戶界面線程,允許執行後台操作而無需操作線程和/或處理程序發布在UI線程上的結果。 AsyncTask的設計是UI thread和Handler一個輔助類,並不構成一個通用線程框架。
這是一個後台下載,前台同步顯示的例子,顯示了asynctask的優勢功能。代碼如下:
private class DownloadFilesTask extends AsyncTask {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }
 



AsyncTask

實現AsyncTask中定義的下面一個或幾個方法:
* onPreExecute(), 該方法將在執行實際的後台操作前被UI 線程調用。可以在該方法中做一些准備工 作,如在界面上顯示一個進度條,或者一些控件的實例化,這個方法可以不用實現。
* doInBackground(Params...), 將在onPreExecute 方法執行後馬上執行,該方法運行在後台線程中。這裡將主要負責執行那些很耗時的後台處理工作。可以調用 publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。
* onProgressUpdate(Progress...),在publishProgress方法被調用後,UI 線程將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。
* onPostExecute(Result), 在doInBackground 執行完成後,onPostExecute 方法將被UI 線程調用,後台的計算結果將通過該方法傳遞到UI 線程,並且在界面上展示給用戶.

* onCancelled(),在用戶取消線程操作的時候調用。在主線程中調用onCancelled()的時候調用。


為了正確的使用AsyncTask類,以下是幾條必須遵守的准則:

  1) Task的實例必須在UI 線程中創建

  2) execute方法必須在UI 線程中調用

  3) 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params...),onProgressUpdate(Progress...)這幾個方法,需要在UI線程中實例化這個task來調用。

  4) 該task只能被執行一次,否則多次調用時將會出現異常

doInBackground方法和onPostExecute的參數必須對應,這兩個參數在AsyncTask聲明的泛型參數列表中指定,第一個為 doInBackground接受的參數,第二個為顯示進度的參數,第第三個為doInBackground返回和onPostExecute傳入的參 數。

//AsyncTask<>的參數類型由用戶設定,這裡設為三個String
//第一個String代表輸入到任務的參數類型,也即是doInBackground()的參數類型
//第二個String代表處理過程中的參數類型,也就是doInBackground()執行過程中的產出參數類型,通過publishProgress()發消息
//傳遞給onProgressUpdate()一般用來更新界面
//第三個String代表任務結束的產出類型,也就是doInBackground()的返回值類型,和onPostExecute()的參數類型
private class task extends AsyncTask



AsyncTask 的執行分為四個步驟,每一步都對應一個回調方法,需要注意的是這些方法不應該由應用程序調用,開發者需要做的就是實現這些方法。在任務的執行過程中,這些方法被自動調用。

* onPreExecute() 當任務執行之前開始調用此方法,可以在這裡顯示進度對話框。
* doInBackground(Params...) 此方法在後台線程 執行,完成任務的主要工作,通常需要較長的時間。在執行過程中可以調用publicProgress(Progress...)來更新任務的進度。
* onProgressUpdate(Progress...) 此方法在主線程 執行,用於顯示任務執行的進度。
* onPostExecute(Result) 此方法在主線程 執行,任務執行的結果作為此方法的參數返回

  1. AsyncTask的三個泛型參數說明(三個參數可以是任何類型)
  2. 第一個參數:傳入doInBackground()方法的參數類型
  3. 第二個參數:傳入onProgressUpdate()方法的參數類型
  4. 第三個參數:傳入onPostExecute()方法的參數類型,也是doInBackground()方法返回的類型

    FileChannel

    FileChannel,是內存與磁盤文件的通道。

    優勢:

    • 多線程並發讀寫,並發性;
    • IO讀寫性能提高(OS負責),也可引做共享內存,減少IO操作,提升並發性;
    • 應用crash,保證這部分內容還能寫的進去文件。在我們調用channel.write(bytebuffer)之後,具體何時寫入磁盤、bytebuffer中內容暫存於哪裡(os cache)等相關一系列問題,就交由OS本身負責了。
      基本使用例:
      import java.io.FileInputStream;  
      import java.io.FileOutputStream;  
      import java.nio.ByteBuffer;  
      import java.nio.channels.FileChannel;  
        
      /** 
       * FileChannel的基本使用。 
       */  
      public class AcquireChannel {  
           public static void main(String[] args) throws Exception {  
               // 根據FileOutputStream獲得通道FileChannel  
               FileChannel channel = new FileOutputStream("D:/a.txt").getChannel();  
               // 字節方式寫入  
               channel.write(ByteBuffer.wrap("hello, NIO world in java!".getBytes()));  
               channel.close();  
                 
               // 根據FileInputStream獲得通道FileChannel   
               channel = new FileInputStream("D:/a.txt").getChannel();  
               // ByteBuffer分配空間,16個字節  
               // 這裡需要知道  byte是1字節, short和char是2字節,int和float是4字節   
               //                          long和double是8字節   1byte=8bit 。  基本只是還是必須記住的。  
               ByteBuffer buff = ByteBuffer.allocate(16);  
               // 字節數組數據裝入buff,  
               channel.read(buff);  
               // 反轉此緩沖區  
               buff.flip();  
               // 逐個輸出,因為分配了16,所以輸出的時候只能輸出hello, NIO world,剩下的  
               // 因為空間關系被截斷。  
               while(buff.hasRemaining()){  
                   System.out.print((char)buff.get());  
               }  
               channel.close();  
           }  
      }  




      Environment
      Environment 是一個提供訪問環境變量的類。


      Environment 包含常量:


      MEDIA_BAD_REMOVAL
      解釋:返回getExternalStorageState() ,表明SDCard 被卸載前己被移除


      MEDIA_CHECKING
      解釋:返回getExternalStorageState() ,表明對象正在磁盤檢查。


      MEDIA_MOUNTED
      解釋:返回getExternalStorageState() ,表明對象是否存在並具有讀/寫權限


      MEDIA_MOUNTED_READ_ONLY
      解釋:返回getExternalStorageState() ,表明對象權限為只讀


      MEDIA_NOFS
      解釋:返回getExternalStorageState() ,表明對象為空白或正在使用不受支持的文件系統。


      MEDIA_REMOVED
      解釋:返回getExternalStorageState() ,如果不存在 SDCard 返回


      MEDIA_SHARED
      解釋:返回getExternalStorageState() ,如果 SDCard 未安裝 ,並通過 USB 大容量存儲共享 返回

      MEDIA_UNMOUNTABLE

      解釋:返回getExternalStorageState() ,返回 SDCard 不可被安裝 如果 SDCard 是存在但不可以被安裝


      MEDIA_UNMOUNTED
      解釋:返回getExternalStorageState() ,返回 SDCard 已卸掉如果 SDCard 是存在但是沒有被安裝


      Environment 常用方法:
      方法:getDataDirectory()
      解釋:返回 File ,獲取 Android 數據目錄。


      方法:getDownloadCacheDirectory()
      解釋:返回 File ,獲取 Android 下載/緩存內容目錄。


      方法:getExternalStorageDirectory()
      解釋:返回 File ,獲取外部存儲目錄即 SDCard


      方法:getExternalStoragePublicDirectory(String type)
      解釋:返回 File ,取一個高端的公用的外部存儲器目錄來擺放某些類型的文件


      方法:getExternalStorageState()
      解釋:返回 File ,獲取外部存儲設備的當前狀態


      方法:getRootDirectory()
      解釋:返回 File ,獲取 Android 的根目錄



      轉載請注明出處:http://write.blog.csdn.net/postedit/18527347 謝謝!
      2014.1.20
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved