1. 程式人生 > >2018-2019-2 20189203 移動平臺應用開發實踐第十周學習總結

2018-2019-2 20189203 移動平臺應用開發實踐第十周學習總結

ace The ont ces horizon 產生 xtend 成了 例如

第39,40,41,42章

第39章 偏好

  • 在Android應用中,我們常需要記錄用戶設置的一些偏好參數,,此時我們就需要用SharedPreferences和Editor將這些信息保存下來,在下次登錄時讀取。
    SharedPreferences保存的數據主要類似於配置信息格式的數據,因此它保存數據的形式為key-value對,下面我們來看下實例代碼。
    首先是界面布局,比較簡單,就是一個普通的登陸界面.
 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:paddingBottom="@dimen/activity_vertical_margin"
 6     android:paddingLeft="@dimen/activity_horizontal_margin"
 7     android:paddingRight="@dimen/activity_horizontal_margin"
 8     android:paddingTop="@dimen/activity_vertical_margin"
 9     tools:context=".MainActivity" >
10 <EditText 
11     android:layout_width="fill_parent"
12     android:layout_height="wrap_content"
13     android:id="@+id/account"
14     />
15 <EditText 
16     android:layout_width="fill_parent"
17     android:layout_height="wrap_content"
18     android:id="@+id/password"
19     android:layout_below="@id/account"
20     />
21 <Button 
22         android:layout_width="fill_parent"
23         android:layout_height="wrap_content"
24         android:layout_below="@id/password"
25         android:text="保存參數"
26         android:id="@+id/save"
27         android:onClick="save"
28  />
29 </RelativeLayout>

這是自定義的Preferences 類,用來實現數據的保存 ,可在Android的內置存儲空間產生一文件。

 1 import android.R.integer;
 2 import android.content.Context;
 3 import android.content.SharedPreferences;
 4 import android.content.SharedPreferences.Editor;
 5 import android.widget.EditText;
 6 
 7 public class Preferences {
 8 
 9     private Context context;
10     public Preferences(Context context)
11     {
12         this.context=context;
13     }
14     
15     
16     public void save(String name, Integer valueOf) 
17     {
18         //保存文件名字為"shared",保存形式為Context.MODE_PRIVATE即該數據只能被本應用讀取
19         SharedPreferences preferences=context.getSharedPreferences("shared",Context.MODE_PRIVATE);
20         
21         Editor editor=preferences.edit();
22         editor.putString("name", name);
23         editor.putInt("age", valueOf);
24         
25         editor.commit();//提交數據
26     }
27 
28 
29 }

下面是Mainactivity的代碼。在activity的oncreate階段我們加載本地的數據。

import java.util.HashMap;
import java.util.Map;

import android.R.integer;
import android.os.Bundle;
import android.app.Activity;
import android.content.SharedPreferences;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

    private EditText account,passworad;
    Preferences prefer;//自定義的類
    SharedPreferences preference; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        account=(EditText)findViewById(R.id.account);
        passworad=(EditText)findViewById(R.id.password);
        
        //獲取本地的數據
       preference=getSharedPreferences("shared", MODE_PRIVATE);
        Map<String, String> map=new HashMap<String, String>();
        map.put("name",preference.getString("name",""));
        map.put("age", String.valueOf(preference.getInt("age", 0)));        
        account.setText(map.get("name"));
        passworad.setText(map.get("age"));
        
    }

    //保存文件的方法
    public void save(View v) {
    String name=account.getText().toString();
    String age=passworad.getText().toString();
    prefer=new Preferences(this);
    prefer.save(name,Integer.valueOf(age));
    Toast.makeText(getApplicationContext(), "保存完成", Toast.LENGTH_SHORT).show();

    }
    
     @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

點擊保存參數,出現保存完成則說明我們已經保存成功了,在下次登錄的時候可以看到這些參數還在。因為記錄文件是在內置空間中的,所以我們在SD卡中找不到該文件,
如果有root權限的手機可以下載個RE文件管理,我們可以再/data/data/的路徑找到很多應用程序的內置文件夾,我們可以在這些文件夾中看到一個shared_prefs文件夾,
裏面就有我們剛剛設置而產生的xml文件。

第40章 操作文件

  • 相對路徑和絕對路徑
    在java中,關於相對路徑和絕對路徑是這樣解釋的,如果你很熟悉這部分以下灰色文字可以跳過:
    絕對路徑是指書寫文件的完整路徑,例如d:\java\Hello.java,該路徑中包含文件的完整路徑d:\java以及文件的全名Hello.java。使用該路徑可以唯一的找到一個文件,不會產生歧義。但是使用絕對路徑在表示文件時,受到的限制很大,且不能在不同的操作系統下運行,因為不同操作系統下絕對路徑的表達形式存在不同。
    相對路徑是指書寫文件的部分路徑,例如\test\Hello.java,該路徑中只包含文件的部分路徑\test和文件的全名Hello.java,部分路徑是指當前路徑下的子路徑,例如當前程序在d:\abc下運行,則該文件的完整路徑就是d:\abc\test。使用這種形式,可以更加通用的代表文件的位置,使得文件路徑產生一定的靈活性。
    在Eclipse項目中運行程序時,當前路徑是項目的根目錄,例如工作空間存儲在d:\javaproject,當前項目名稱是Test,則當前路徑是:d:\javaproject\Test。在控制臺下面運行程序時,當前路徑是class文件所在的目錄,如果class文件包含包名,則以該class文件最頂層的包名作為當前路徑。
    這是java在多數操作系統中這樣操作,很顯然是要我們盡可能的使用相對路徑,但是在安卓中,其實多數情況下我們都是使用的絕對路徑。為什麽呢?註意上面說到相對路徑是以當前項目所在路徑為當前路徑,但在安卓中我們是不可能在項目所在路徑目錄下做任何操作的,因為普通java中我們的項目創建於服務器(pc也算是服務器),運行於服務器,我們當然能在服務器操作自己的文件目錄。但是安卓開發中,我們的項目一般是創建於自己工作的電腦,而運行於手機,既然apk已經運行於手機了,那項目就已經部署到手機上了,應該以apk在手機上的位置來確定相對路徑,但我們好像們沒有辦法操作這個路徑的,因為apk是在system目錄下,就算可以操作,在這個目錄下存取文件也是沒有意義的,比如我寫一個相冊程序,圖片肯定是放在外部存儲中,而如果我要保存一個應用的一些設置數據,我是放在內部存儲的data目錄下,因此其實在安卓文件管理中,我們都是在操作絕對路徑。
  • File類
    操作一個文件(讀寫,創建文件或者目錄)是通過File類來完成的,這個操作和java中完全一致。
    外部存儲external storage和內部存儲internal storage
    1.內部存儲:
    註意內部存儲不是內存。內部存儲位於系統中很特殊的一個位置,如果你想將文件存儲於內部存儲中,那麽文件默認只能被你的應用訪問到,且一個應用所創建的所有文件都在和應用包名相同的目錄下。也就是說應用創建於內部存儲的文件,與這個應用是關聯起來的。當一個應用卸載之後,內部存儲中的這些文件也被刪除。從技術上來講如果你在創建內部存儲文件的時候將文件屬性設置成可讀,其他app能夠訪問自己應用的數據,前提是他知道你這個應用的包名,如果一個文件的屬性是私有(private),那麽即使知道包名其他應用也無法訪問。 內部存儲空間十分有限,因而顯得可貴,另外,它也是系統本身和系統應用程序主要的數據存儲所在地,一旦內部存儲空間耗盡,手機也就無法使用了。所以對於內部存儲空間,我們要盡量避免使用。Shared Preferences和SQLite數據庫都是存儲在內部存儲空間上的。內部存儲一般用Context來獲取和操作。
    getFilesDir()獲取你app的內部存儲空間,相當於你的應用在內部存儲上的根目錄。
    如果是要創建一個文件,如下
    File file = newFile(context.getFilesDir(), filename);
    安卓還為我們提供了一個簡便方法 openFileOutput()來讀寫應用在內部存儲空間上的文件,下面是一個向文件中寫入文本的例子:
String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;
try{
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch(Exception e) {
e.printStackTrace();
}

總結一下文件相關操作,可以得出以下三個特點:

  1. 文件操作只需要向函數提供文件名,所以程序自己只需要維護文件名即可;
  2. 不用自己去創建文件對象和輸入、輸出流,提供文件名就可以返回File對象或輸入輸出流
  3. 對於路徑操作返回的都是文件對象。

2.外部存儲:
最容易混淆的是外部存儲,如果說pc上也要區分出外部存儲和內部存儲的話,那麽自帶的硬盤算是內部存儲,U盤或者移動硬盤算是外部存儲,因此我們很容易帶著這樣的理解去看待安卓手機,認為機身固有存儲是內部存儲,而擴展的T卡是外部存儲。比如我們任務16GB版本的Nexus 4有16G的內部存儲,普通消費者可以這樣理解,但是安卓的編程中不能,這16GB仍然是外部存儲。
所有的安卓設備都有外部存儲和內部存儲,這兩個名稱來源於安卓的早期設備,那個時候的設備內部存儲確實是固定的,而外部存儲確實是可以像U盤一樣移動的。但是在後來的設備中,很多中高端機器都將自己的機身存儲擴展到了8G以上,他們將存儲在概念上分成了"內部internal" 和"外部external" 兩部分,但其實都在手機內部。所以不管安卓手機是否有可移動的sdcard,他們總是有外部存儲和內部存儲。最關鍵的是,我們都是通過相同的api來訪問可移動的sdcard或者手機自帶的存儲(外部存儲)。
外部存儲雖然概念上有點復雜,但也很好區分,你把手機連接電腦,能被電腦識別的部分就一定是外部存儲。
外部存儲中的文件是可以被用戶或者其他應用程序修改的,有兩種類型的文件(或者目錄):
1.公共文件Public files:文件是可以被自由訪問,且文件的數據對其他應用或者用戶來說都是由意義的,當應用被卸載之後,其卸載前創建的文件仍然保留。比如camera應用,生成的照片大家都能訪問,而且camera不在了,照片仍然在。
如果你想在外存儲上放公共文件你可以使用getExternalStoragePublicDirectory()

public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = newFile(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if(!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
returnfile;
}

在上面的代碼中我們創建獲得了存放picture的目錄,並且新創建一個albumName文件。
如果你的api 版本低於8,那麽不能使用getExternalStoragePublicDirectory(),而是使用Environment.getExternalStorageDirectory(),他不帶參數,也就不能自己創建一個目錄,只是返回外部存儲的根路徑。
2.私有文件Private files:其實由於是外部存儲的原因即是是這種類型的文件也能被其他程序訪問,只不過一個應用私有的文件對其他應用其實是沒有訪問價值的(惡意程序除外)。外部存儲上,應用私有文件的價值在於卸載之後,這些文件也會被刪除。類似於內部存儲。
創建應用私有文件的方法是Context.getExternalFilesDir(),如下:

public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app's private pictures directory.
File file = newFile(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if(!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
returnfile;
}

所有應用程序的外部存儲的私有文件都放在根目錄的Android/data/下,目錄形式為/Android/data//

第41章 操作數據庫

1、數據庫的創建:

private static final String TABLENAME = "student";
private static final String CREATETABLE = "CREATE TABLE " + TABLENAME +
        "(_id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,age INTEGER)";

public void creatTable(View view){
    /**
     * 創建數據庫
     * 參數一:數據庫名
     * 參數二:模式,一般為MOE_PRIVATE
     * 參數三:遊標工廠對象,一般寫null,表示系統自動提供
     */
    SQLiteDatabase db = this.openOrCreateDatabase("text.db",MODE_PRIVATE,null);
    db.execSQL(CREATETABLE);
    db.close();
}

2、數據庫表的創建和數據的添加:

public void insertData(View view){
    SQLiteDatabase db = this.openOrCreateDatabase("text.db",MODE_PRIVATE,null);
    ContentValues values = new ContentValues();
    values.put("name","張三");
    values.put("age",18);
    /**
     *插入數據
     * 參數一:要插入的表名
     * 參數二:要插入的空數據所在的行數,第三個參數部位空,則此參數為null
     * 參數三:要插入的數據
     */
    db.insert(TABLENAME,null,values);
    ContentValues values1 = new ContentValues();
    values1.put("name","李四");
    values1.put("age",21);
    db.insert(TABLENAME,null,values1);
    db.close();
}

3、數據庫的更新:

public void updateData(View view){
    SQLiteDatabase db = this.openOrCreateDatabase("text.db",MODE_PRIVATE,null);
    ContentValues values = new ContentValues();
    values.put("name","趙四");
    values.put("age",43);
    /**
     * 數據的更新
     * 參數一:要更新的數據所在的表名
     * 參數二:新的數據
     * 參數三:要更新數據的查找條件
     * 參數四:條件的參數
     */
    db.update(TABLENAME,values,"_id=?",new String []{"2"});
    db.close();
}

4、數據的查找:

public void queryData(View view){
    SQLiteDatabase db = this.openOrCreateDatabase("text.db",MODE_PRIVATE,null);
    //查詢部分數據
    Cursor cursor = db.rawQuery("select * from " + TABLENAME + "where name=?",new String []{"張三"});
    //查詢全部數據
    Cursor cursor1 = db.rawQuery("select * from " + TABLENAME ,null);
    //將遊標移到第一行
    cursor1.moveToFirst();
    //循環讀取數據
    while(!cursor1.isAfterLast()){
        //獲得當前行的標簽
        int nameIndex = cursor1.getColumnIndex("name");
        //獲得對應的數據
        String name = cursor1.getString(nameIndex);
        int ageIndex = cursor1.getColumnIndex("age");
        int age = cursor1.getInt(ageIndex);
        Log.d(TAG, "name:"+ name +"age: "+age);
        //遊標移到下一行
        cursor1.moveToNext();
    }
    db.close();
}

5、數據的刪除:

public void delectData(View view){
    SQLiteDatabase db = this.openOrCreateDatabase("text.db",MODE_PRIVATE,null);
    //要刪除的數據
    db.delete(TABLENAME,"name = ?",new String[]{"趙四"});
    db.close();
}

第42章 獲取圖片

在Andorid系統中所有的文件路徑都保存在一個數據庫中,位於data/data/com.android.providers.media文件夾下的external.db
裏面的files表就有我們需要的內容,這個表包含了機器所有的文件。接下來只要選擇合適的sql語句來獲取我們需要的內容就行了。

2018-2019-2 20189203 移動平臺應用開發實踐第十周學習總結