20189200餘超 2018-2019-2 移動平臺應用開發實踐第十週做業

20189200餘超 2018-2019-2 移動平臺應用開發實踐第十週做業

偏好

在Android應用中,咱們常須要記錄用戶設置的一些偏好參數,,此時咱們就須要用SharedPreferences和Editor將這些信息保存下來,在下次登陸時讀取。java

SharedPreferences保存的數據主要相似於配置信息格式的數據,所以它保存數據的形式爲key-value對,下面咱們來看下實例代碼。android

首先是界面佈局,比較簡單,就是一個普通的登錄界面.sql

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
<EditText 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/account"
    />
<EditText 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/password"
    android:layout_below="@id/account"
    />
<Button 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/password"
        android:text="保存參數"
        android:id="@+id/save"
        android:onClick="save"
 />
</RelativeLayout>

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

import android.R.integer;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.widget.EditText;

public class Preferences {

    private Context context;
    public Preferences(Context context)
    {
        this.context=context;
    }
    
    
    public void save(String name, Integer valueOf) 
    {
        //保存文件名字爲"shared",保存形式爲Context.MODE_PRIVATE即該數據只能被本應用讀取
        SharedPreferences preferences=context.getSharedPreferences("shared",Context.MODE_PRIVATE);
        
        Editor editor=preferences.edit();
        editor.putString("name", name);
        editor.putInt("age", valueOf);
        
        editor.commit();//提交數據
    }
}

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

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文件。
app

操做空間

咱們先來考慮這樣一個問題:ide

打開手機設置,選擇應用管理,選擇任意一個App,而後你會看到兩個按鈕,一個是清除緩存,另外一個是清除數據,那麼當咱們點擊清除緩存的時候清除的是哪裏的數據?當咱們點擊清除數據的時候又是清除的哪裏的數據?讀完本文相信你會有答案。工具

在android開發中咱們經常聽到這樣幾個概念,內存,內部存儲,外部存儲,不少人經常將這三個東西搞混,那麼咱們今天就先來詳細說說這三個東西是怎麼回事?

內存,咱們在英文中稱做memory,內部存儲,咱們稱爲InternalStorage,外部存儲咱們稱爲ExternalStorage,這在英文中本不會產生歧義,可是當咱們翻譯爲中文以後,前兩個都簡稱爲內存,因而,混了。

那麼究竟什麼是內部存儲什麼是外部存儲呢?

首先咱們打開DDMS,有一個File Explorer,以下:

完全理解android中的內部存儲與外部存儲0

這裏有三個文件夾須要咱們重視,一個是data,一個是mnt,一個是storage,咱們下面就詳細說說這三個文件夾。

1.內部存儲

data文件夾就是咱們常說的內部存儲,當咱們打開data文件夾以後(沒有root的手機不能打開該文件夾),裏邊有兩個文件夾值得咱們關注,以下:

一個文件夾是app文件夾,還有一個文件夾就是data文件夾,app文件夾裏存放着咱們全部安裝的app的apk文件,其實,當咱們調試一個app的時候,能夠看到控制檯輸出的內容,有一項是uploading .....就是上傳咱們的apk到這個文件夾,上傳成功以後纔開始安裝。另外一個重要的文件夾就是data文件夾了,這個文件夾裏邊都是一些包名,打開這些包名以後咱們會看到這樣的一些文件:

1.data/data/包名/shared_prefs
2.data/data/包名/databases
3.data/data/包名/files

4.data/data/包名/cache

若是打開過data文件,應該都知道這些文件夾是幹什麼用的,咱們在使用sharedPreferenced的時候,將數據持久化存儲於本地,其實就是存在這個文件中的xml文件裏,咱們App裏邊的數據庫文件就存儲於databases文件夾中,還有咱們的普通數據存儲在files中,緩存文件存儲在cache文件夾中,存儲在這裏的文件咱們都稱之爲內部存儲。

2.外部存儲

外部存儲纔是咱們平時操做最多的,外部存儲通常就是咱們上面看到的storage文件夾,固然也有多是mnt文件夾,這個不一樣廠家有可能不同。

通常來講,在storage文件夾中有一個sdcard文件夾,這個文件夾中的文件又分爲兩類,一類是公有目錄,還有一類是私有目錄,其中的公有目錄有九大類,好比DCIM、DOWNLOAD等這種系統爲咱們建立的文件夾,私有目錄就是Android這個文件夾,這個文件夾打開以後裏邊有一個data文件夾,打開這個data文件夾,裏邊有許多包名組成的文件夾。

說到這裏,我想你們應該已經能夠分清楚什麼是內部存儲什麼是外部存儲了吧?好,分清楚以後咱們就要看看怎麼來操做內部存儲和外部存儲了。

3.操做存儲空間

首先,通過上面的分析,你們已經明白了,什麼是內部存儲,什麼是外部存儲,以及這兩種存儲方式分別存儲在什麼位置,通常來講,咱們不會本身去操做內部存儲空間,沒有root權限的話,咱們也無法操做內部存儲空間,事實上內部存儲主要是由系統來維護的。不過在代碼中咱們是能夠訪問到這個文件夾的。因爲內部存儲空間有限,在開發中咱們通常都是操做外部存儲空間,Google官方建議咱們App的數據應該存儲在外部存儲的私有目錄中該App的包名下,這樣當用戶卸載掉App以後,相關的數據會一併刪除,若是你直接在/storage/sdcard目錄下建立了一個應用的文件夾,那麼當你刪除應用的時候,這個文件夾就不會被刪除。

通過以上的介紹,咱們能夠總結出下面一個表格:

一目瞭然,什麼是內部存儲,什麼是外部存儲。

若是按照路徑的特徵,咱們又能夠將文件存儲的路徑分爲兩大類,一類是路徑中含有包名的,一類是路徑中不含有包名的,含有包名的路徑,由於和某個App有關,因此對這些文件夾的訪問都是調用Context裏邊的方法,而不含有包名的路徑,和某一個App無關,咱們能夠經過Environment中的方法來訪問。以下圖:

操做數據庫

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;

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

        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 3); // 執行這句並不會建立數據庫文件
        Button btnCreateDatabase = (Button) findViewById(R.id.button);
        btnCreateDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase(); // 執行這句纔會建立數據庫文件
            }
        });

    }
}
public class MyDatabaseHelper extends SQLiteOpenHelper {

    public static final String CREATE_BOOK = "create table book (" +
            "id integer primary key autoincrement, " +
            "author text, " +
            "price real," +
            "pages integer, " +
            "name text)";

    private Context mContext;

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);

        mContext = context;
    }

    /**
     * 數據庫已經建立過了, 則不會執行到,若是不存在數據庫則會執行
     * @param db
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK); // 執行這句纔會建立表

        Toast.makeText(mContext, "create succeeded", Toast.LENGTH_SHORT).show();

    }

    /**
     * 建立數據庫時不會執行,增大版本號升級時纔會執行到
     * @param db
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 在這裏面能夠把舊的表 drop掉 重新建立新表,
        // 但若是數據比較重要更好的作法仍是把舊錶的數據遷移到新表上,好比升級qq聊天記錄被刪掉確定招罵
        Toast.makeText(mContext, "onUpgrade oldVersion:" + oldVersion + " newVersion:" + newVersion, Toast.LENGTH_SHORT).show();
    }
}

驗證數據庫文件是否存在的方法看最後部分

剩下的工做就是對數據庫表的增刪改查了

首先經過下面的代碼得到一個引用以便操做數據庫

1 SQLiteDatabase db = dbHelper.getWritableDatabase();

對於增刪改均可以用 db.execSQL(String sql); 來執行sql語句。 例如增長一條記錄

1 db.execSQL("insert into book(name , author, pages, price) values("Android數據庫操做指南", "panda fang", 200, 35.5)");

遇到字符串要轉義 有沒有以爲很蛋疼, 用下面的方法就好多了

1 db.execSQL("insert into book(name , author, pages, price) values(?, ? ,? ,? )", new String[]{"Android數據庫操做指南", "panda fang", "200", "35.5"});

sql 中用 ? 佔位 後面傳入真正的參數, 因爲在建立表的時候已經約定pages 和 price字段的數據類型爲integer和real, 雖然代碼中寫的是字符串並不影響,存入數據庫會自動處理的。數組嘛,必須與其餘的元素類型一致。 這第二個方式是 execSQL(String sql)的重載方法 api是 public void execSQL(String sql, Object[] bindArgs) throws SQLException

對於查詢則要使用 rawQuery(String sql, String[] selectionArgs) , 由於 execSQL返回void ,而查詢須要訪問查詢結果。方法以下:

Cursor cursor =  db.rawQuery("select * from book", null);
while (cursor.moveToNext())
{
    String name = cursor.getString(cursor.getColumnIndex("name"));
    String author =  cursor.getString(cursor.getColumnIndex("author"));
    Log.i(TAG, "name:" + name + " author:" + author);
}
cursor.close();

如何檢查數據庫文件是否存在,以及檢查表中的數據呢。

前提是使用模擬器或者root過的真機。從 android studio 菜單中 Tools -> Android -> Android Device Monitor -> File Explorer 找到 data/data/程序包名/databases 目錄

查看是否存在數據庫文件。若是存在能夠導出到電腦上, 用 如下工具查看數據庫中的表

獲取圖片

import java.io.FileNotFoundException;

import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;

import com.maikefengchao.daixu.R;

public class WriteArticle_CompeterelayActivity extends BaseActivity {
    private ImageView im_upload_img;

    @Override
    public void initView(Bundle savedInstanceState){
        setContentView(R.layout.view_write_competerelay);

        im_upload_img = (ImageView)findViewById(R.id.write_competerelay_cover_iv);
    }

    @Override
    protected void setListener() {
        im_upload_img.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                /* 開啓Pictures畫面Type設定爲image */
                intent.setType("image/*");
                /* 使用Intent.ACTION_GET_CONTENT這個Action */
                intent.setAction(Intent.ACTION_GET_CONTENT);
                /* 取得相片後返回本畫面 */
                startActivityForResult(intent, 1);
            }
        });
    }

    @Override
    protected void processLogic(Bundle saveInstanceState) {

    }


    //獲取本地圖片
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            Uri uri = data.getData();
            String img_url = uri.getPath();//這是本機的圖片路徑
            ContentResolver cr = this.getContentResolver();
            try {
                Bitmap bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));
                ImageView imageView = (ImageView) findViewById(R.id.write_competerelay_cover_iv);
                /* 將Bitmap設定到ImageView */
                imageView.setImageBitmap(bitmap);
            } catch (FileNotFoundException e) {
                Log.e("Exception", e.getMessage(),e);
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }
}

statistics.sh

相關文章
相關標籤/搜索