Android 基礎四五六之:四大組件 Android 四大組件 一、Activity Android 五大存儲 Android 六大布局 最後

Android 四大組件

android四大組件分別是:Activity, service,content provider,broadcast receiver

今天就帶大家詳細的學一波基本功,需要Android架構完整學習資料的朋友可以【直接點擊此處】去文件夾取,免費分享大家。

一、Activity

1、概念:

android 中,Activity 相當於一個頁面,可以在Activity中添加Button、CheckBox 等控件,一個android 程序有多個Activity組成。

2、生命週期:

3、四中啓動模式

Standard 模式 : standard 模式是android 的默認啓動模式,在這種模式下,activity可以有多個實例,每次啓動Activity,無論任務棧中是否已經存在這個activity的實例,系統都會創建一個新的activity實例。

SingleTop 模式: 棧頂模式,當一個singleTop模式的activity 已經位於棧頂時,再去啓動它時,不在創建實例,如果不在棧頂,就會創建實例。

SingleTask 模式 : 單任務模式,如果啓動的activity 已經存在於 任務棧中,則會將activity移動到棧頂,並將上面的activity出棧,否則創建新的實例

SingleInstance 模式 :單實例模式,一個activity 一個棧。

4、三種跳轉方式

顯示啓動 :
Intrent 內部直接聲明要啓動的activity所對應的的class

Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intnet);

隱式啓動

進行三個匹配,一個是activity,一個是category,一個是data,全部或者部分匹配,應用於廣播原理

清單文件中 裏配置activity屬性,activity的名字要和跳轉內容一樣

<activity 
    android:name="com.exanple.android.tst.secondActivity"
    android:label = @string/title>
    <intent=filter>
        <action android:name="com.exanple.android.tst.secondActivity/>
        <category android:name="android.intent.category.DEFAULT"/>
    <intent-filter/>
</activity>

在需要跳轉的地方

Intent intent = new Intent("com.example.android.tst.secondActivity");
startActivity(intnet);

跳轉後再返回,能獲取返回值

Intent in = new Intent(MainActivity.this,OtehrActivity.class);
in.putExtra("a",a);
startActivityForResult(in,1000);

在OTherActivity中設置返回值

Intent int = new Intent();
int.putExtra("c",c);
setResult(1001,int);
finish();

在MainActivity中獲取返回值

@Override
protected void onActivityResult(int requestCode, int resultCode ,Intent data) {
    super.onActivityResult(requestCode,resultCode,data);
    if(requestCode == 1000){
        if(resultCode == 1001){
            int c = data.getExtra("c",0);
        }
    }
}

Service

定義一個Server

項目內Server包 右鍵 --> New --> Service --> Service 或者直接創建Class類,繼承Service並重寫IBinder方法

public class MyService extends Service{
    
    public MyService(){
        
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    @Override
    public void onCreate() {
        super.onCreate();
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
    
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
    }
}

重寫Service的 onCreate()、onStartCommand()和onDestory()方法。其中 onCreate() 方法在服務創建的時候調用、onStartCommand() 方法會在每次服務啓動的時候調用、onDestory() 方法會在服務銷燬的時候調用。
通常情況下,如果我們希望服務一旦啓動就立刻去執行任務,就可以將邏輯卸載onStartCommand() 方法裏。
另外需要注意的是,每個服務都需要在Androidmanifest.xml 中進行註冊才能生效:

<application
    ....>
    ...
    <service
        android:name=".MyService"
        android:enabled="true"
        android:exported="true">
    </service>
</application>

啓動和停止服務

啓動服務:

Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); //啓動服務

停止服務:

Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); //停止服務

使用前臺服務

前臺服務與普通服務的最大區別在於,它會一直有一個正在運行的圖標在系統的狀態欄中,下拉狀態欄後可以看到更加詳細的內容,非常類似於通知的效果。

public class MyService extends Service{
    Intent intent = new Intent(this, MainActivity.class);
    PendingIntent pi = PendingIntent.getActivity(this, 0 , intent, 0);
    Notification notification  = new NotificationCompat.Builder(this)
        .setContentTitle(" this is content titile")
        .setContentText("this is content text")
        .setWhen(System.currentTimeMillis())
        .setSmallIcon(R.mipmap.ic_launcher);
        .setLargeIcon(BitmapFactory.decodeResource(getResource(),
            R.mipmap.ic_launcher))
        .setContentIntent(pi)
        .build();
    startForeground(1,notification);
}

構造一個Notification對象後並沒有使用NotificationManager 來講通知顯示出來,而是調用了startForeground()方法,該方法會將MyService變成一個前臺服務,並在系統狀態欄中顯示出來。

使用IntentService

服務中的代碼都默認運行在主線程中,如果直接在服務中執行耗時操作很容易出現ANR(Application not Responding)
所以這個時候需要用到Android多線程編程技術,我們應該在服務的每個具體的方法裏啓動一個子線程,然後在這裏去處理那些耗時的操作:

public class MyService extends Service{
    ...
    @Override
    public int onStartCommand(Intent intent , int flags, int startId){
        new Thread(new Runnable(){
            public void run(){
                //處理具體的邏輯
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }
}

但是,這種服務一旦啓動之後,就會一直處於運行狀態,必須調用stopService()或者stopSelf()方法才能讓服務停止下來,所以,如果想要實現讓一個服務在執行完畢後自動停止的功能,就可以這樣寫:

public class MySerivce extends Servcie{
    ...
    @Override
    public int onStartCommand(Intent intent, int flats , int startId){
        new Thread(new Runnable(){
            public void run(){
                //處理具體的邏輯
                stopSelf();
            }
        });
    }
}

雖說這樣的寫法並不複雜,但是總會有一些程序員忘記開啓線程或者忘記調用stopSelf() 方法。爲了簡單創建一個異步、會自動停止的服務。Android專門提供了一個IntentService類

public class MyIntentService extends IntentService{
    public MyIntentService(){
        super("MyIntentService");  //調用父類的有參構造方法
    }
    @Override
    protected void onHandleIntent(Intent intent){   
        //打印當前的線程ID
        Log.e("mylog","Thread id is” + Thread.cuttentThread().getId();
    }
    @Override
    public void onDestory(){
        super.onDestory();
        Log.e("mylog","on Destory executed");
    }
}

首先這裏提供一個無參的構造方法,並且必須在其內部調用父類的有參構造方法。然後要在子類中去實現onHandleIntent() 這個抽象方法,在這個方法中可以去處理一些邏輯,而且不用擔心ANR,因爲這個方法已經是在子線程中運行了。
IntentService線程的調用:

Intent intent = new Intent(this, MyIntentService.class);
startServcie(intent);

如此,線程就會自動啓動並執行邏輯,執行完畢後自動關閉。這就是IntentService 的好處,能夠自動開啓和關閉;

Content Provider

對於每一個應用程序來說,如果想要訪問內容提供器中共享的數據,就一定要藉助ContentResolver 類,可以通過Context中的getContentResolver() 方法獲取該類的實例。ContentResolver中提供了一系列的方法用於對數據進行CRUD操作,其中insert() 方法用於添加數據,update() 方法用於更新數據,delete() 方法用於刪除數據,query() 方法用於查詢數據。

不同於SQLiteDatabase,ContentResolver 中的增刪改查都是接收一個URl參數,這個參數被稱爲內容URL。內容URL給內容提供器中的數據建立了唯一標識符,它主要由兩部分組成:authority 和 path 。authority 是用於對不同的應用程序做區分的,一般爲了避免衝突,都會採用程序包名的方式進行命名。path則是用於對同一應用程序中不同的表做區分,通常都會添加到authority後面:

content://com.example.app.provider/table1
content://com.example.app.provider/table2

在使用內容URL作爲參數的時候,需要將URL轉換成URL對象:

Uri uri = Uri.parse("content://com.example.app.provider/table1")

現在我們就可以使用這個uri對象來查詢talbe1表中的數據了:

Cursor cursor = getContentResolver().query(
    uri,
    projection,
    selection,
    selectionArgs,
    sortOrder
);

對應參數的解釋:

查詢完之後,就可以從遊標中取值了:

if(cursor != null){
    while(cursor.moveToNext()) {
        String column1 = cursor.getString(cursor.getColumnIndex("column1"));
        int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
    }
    cursor.close();
}

增刪改查

添加數據

ContentValues values = new ContentValues();
values.put(“column1”, "text");
values.put("column2", 1);
getContentResolver().insert(uri, values);

更新數據

ContentValues valuse = new ContentValues();
valuse.put("column1", "");
getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new String[]{"text", 1});

刪除數據

getContentResolver().delete(uri , "column2 = ?", new String[]{ "1"});

實例.

讀取系統聯繫人

讀取系統聯繫人需要聲明權限,如果系統是6.0以後的,需要申請運行時權限

if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) 
    != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
    }else {
        readContacts();  //讀取聯繫人
    }
private void readContacts(){
    Cursor cursor = null;
    try{
        //查詢聯繫人數據
        cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);
        if(cursor!=null){
            while(cursor.moveToNext()){
                //獲取聯繫人姓名
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                //獲取聯繫人電話號碼
                String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                list.add(name+"\n"+number);
            }
        }
    }catch(Exception e){
        e.printStackTrace()
    }finally{
        if(cursor != null){
            cursor.close();
        }
    }
}

@Override
public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults){
    switch(requestCode){
        case 1:
            if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                readContacts();
            }else {
                //您拒絕了權限
            }
    }
}

創建自己的內容提供器

創建自己的內容提供器,需要去繼承 ContentProvider 類,ContentProvider 類中有6個抽象方法,我們在使用子類繼承它的時候,需要將這6個方法全部重寫。

public class MyProvider extends ContentProvider{
    @Override
    public boolean onCreate() {
        return false;
    }
    @Override
    public Cursor query(Uri uri, String[] projection, Stirng selection, String[] selectionArgs, String sortOrder){
        return null;
    }
    @Overrride
    public Uri insert(Uri uri , ContentValues values){
        return null;
    }
    @Override
    public int update(Uri uri, ContentValuse values, String selection, String[] selectionArgs){
        return 0;
    }
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs){
        return 0;
    }
    @Override
    public String getType(Uri uri){
        return null;
    }
}

URI 的主要格式有以下兩種

content://com.example.app.provider/table1
content://com.example.app.provider/table1/1

* : 表示匹配任意長度的任意字符
# : 表示匹配任意長度的數字

//一個能夠匹配任意表的內容URI格式就可以寫成:
content://com.example.app.provider/*
//一個能夠匹配表中任意一行數據的內容URI格式就可以寫成:
content://com.example.app.provider/table1/#

Broadcast Receiver

android 廣播分爲兩個角色:廣播發送者、廣播接收者
android 廣播:

1),用於不同組件間的通信(含:應用內/不同應用之間)
2),用於多線程通信
3),與android系統的通信

自定義廣播接收者

繼承BroadcastReceive 基類
必須重寫抽象方法onReceive()方法

1,廣播接收器收到相應廣播後,會自動調用onReceive() 方法
2,一般情況下,onReceive方法會會涉及與其他組件之間的交互,如 發送Notiotification,啓動server等
3,默認情況下,廣播接收器運行在UI線程,因此,onReceive方法不能執行耗時操作,否則將導致ANR

廣播接收器註冊

註冊的方式有兩種:靜態註冊、動態註冊
靜態註冊

註冊方式:在AndroidManifest.xml 裏通過<receive 標籤聲明
屬性說明

<receiver
    android:enable="true"/"false"
    //此broadcastReceiver 是否接受其他應用發出的廣播
    //默認值時由receiver 中d有無inter-filter決定,如果有,默認true,否則默認false
    android:exported="true"/"false"
    android:icon="drawable resource"
    android:label="string resource"
    //繼承BroadcastReceiver子類的類名
    android:name=".mBroadcastReceiver"
//具有相應權限的廣播發送者發送的廣播才能被此BroadcastReceiver所接收;
    android:permission="string"
//BroadcastReceiver運行所處的進程
//默認爲app的進程,可以指定獨立的進程
//注:Android四大基本組件都可以通過此屬性指定自己的獨立進程
    android:process="string" >

//用於指定此廣播接收器將接收的廣播類型
//本示例中給出的是用於接收網絡狀態改變時發出的廣播
 <intent-filter>
    <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
 </intent-filter>
 </receiver>

註冊示例:

<receiver 
    //此廣播接收者類是mBroadcastReceiver
    android:name=".mBroadcastReceiver" >
    //用於接收網絡狀態改變時發出的廣播
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

當此APP首次啓動時,系統會自動實例化mBroadcastReceiver類,並註冊到系統中。

動態註冊

註冊方式:在代碼中調用Context.registerReceiver() 方法
具體代碼如下:

    // 1. 實例化BroadcastReceiver子類 &  IntentFilter
     mBroadcastReceiver mBroadcastReceiver = new mBroadcastReceiver();
     IntentFilter intentFilter = new IntentFilter();

    // 2. 設置接收廣播的類型
    intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);

    // 3. 動態註冊:調用Context的registerReceiver()方法
     registerReceiver(mBroadcastReceiver, intentFilter);


//動態註冊廣播後,需要在相應位置記得銷燬廣播
unregisterReceiver(mBroadcastReceiver);

特別注意

動態廣播最好在onResume中註冊, onPause註銷
原因:
1,對於動態廣播,有註冊必然得有註銷,否則會導致內存泄漏
2,onPause在App死亡前一定會被執行,從而保證app死亡前一定會被註銷,從而防止內存泄漏

兩種註冊方式的區別

廣播的發送
廣播的發送 = 廣播發送者 將此廣播的意圖(intent)通過 sendBroasdcast() 方法發送出去
廣播的類型

普通廣播 系統廣播 有序廣播 粘性廣播 App 應用內廣播

特別注意:

對於不同註冊方式的廣播接收器回調OnReceive(Context context,Intent intent)中的context返回值是不一樣的:

對於靜態註冊(全局+應用內廣播),回調onReceive(context,
intent)中的context返回值是:ReceiverRestrictedContext;
對於全局廣播的動態註冊,回調onReceive(context, intent)中的context返回值是:Activity
Context;
對於應用內廣播的動態註冊(LocalBroadcastManager方式),回調onReceive(context,
intent)中的context返回值是:Application Context。
對於應用內廣播的動態註冊(非LocalBroadcastManager方式),回調onReceive(context,
intent)中的context返回值是:Activity Context;

Android 五大存儲

SharedPreferences 方式

SharedPreferences 是使用鍵值對的方式進行存儲數據的。
想要使用SharedPreferences 來存儲數據,首先主要獲取到SharedPreferences 對象。Android提供了三種方法用於獲取SharedPreferences對象:
1,Context類中的getSharedPreferences()方法

//此方法接收兩個參數,一個參數用於指定SharedPreferences文件的名稱,如果指定的文件不存在則會創建一個,SharedPreferences文件都是存放在/data/data/<package name>/shared_prefs/目錄下
//第二個參數用於指定操作模式,目前只有MODE_PRIVATE這種模式,和直接傳入0效果相同
SharedPreferences.Editor editor = getSharedPreferences("data",MODE_PRIVATE).edit();
editor.putString("name", "Tom");
editor.putInt("age",13);
editor.putBoolean("married",false);
editor.apply();

2,Activity類中的getPreferences()方法

//這個方法和Context中的getSharedPreferences()方法很類似,不過它只接收一個操作模式,因爲使用這個方法時會自動將當前活動的類名作爲SharedPreferences的文件名

3,PreferencesManager類中的getDefaultSharedPreferences()方法

//這是一個靜態方法,它接收一個Context參數,並自動使用當前應用程序的包名作爲前綴來命名SharedPreferences文件

得到了SharedPreferences對象後, 就可以開始想SharedPreferences文件中存儲數據了,主要可以分爲三步:
(1)調用SharedPreferences對象的edit()方法來獲取一個SharedPreferences.Editor對象
(2)向SharedPreferences.Editor 對象中添加數據,比如添加一個布爾值,可以使用putBoolean() 方法
(3)調用apply()方法的添加的數據提交,從而完成數據存儲操作

SharedPreferences中讀取數據

SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE   );
String name = pref.getString("name","");
int age = pref.getInt("age",0);
boolean married = pref.getBoolean("married", false);

文件存儲方式

SQList 存儲方式

Android 爲了讓我們能夠更加方便的管理數據庫,專門提供了一個SQLiteOpenHelper 幫助類,藉助這個類可以非常簡單的將數據庫進行創建好升級。

SQLiteOpenHelper 中有兩個非常重要的實例方法,getReadableDatabase() 和 getWritableDatabase() 。這兩個方法可以創建或者打開一個現有的數據庫(如果數據庫存在則直接打開,否則創建一個新的數據庫),並返回一個可對數據庫進行讀寫操作的對象。不同的是,當數據庫不可寫入(如磁盤空間已滿),getReadableDatabase方法返回的對象將以只讀的方式打開數據庫,而getWeitableDatabase則出現異常

例子(在指定路徑下創建數據庫文件 .db )

public class MainActivity extends Activity {
    public static final String PATH_ONE = "KogBill";
    public static final String PATH_NAME = "KogBill.db";
    private SQLiteDatabase db;    //聲明SQLiteDatabase ,該對象可以操作數據庫

    String path = Environment.getExternalStorageDirectory().getAbsolutePath();
    String path1 = path + File.separator + PATH_ONE;   //需要創建的路徑
    String path2 = path + File.separator + PATH_ONE + 
            File.separator + PATH_NAME;                             //需要創建的文件

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        File f = new File(path1);
        if( !f.exists()){  //創建數據庫文件路徑
            f.mkdirs();
        }   
        //實例化MySQLiteHelper ,創建指定目錄下數據庫文件,並創建表
        MySQLiteHelper mSQL = new MySQLiteHelper(MainActivity.this, path2);
        db = mSQL.getWritableDatabase();
    }

    class MySQLiteHelper extends SQLiteOpenHelper{
            private static final int DATABASE_VERSION = 1;//數據庫版本號
            private static final String CREATE_TABLE = "create table kog_bill ("
                    + "_id integer primary key autoincrement,"
                    + "date text, "
                    + "breakfast text, "
                    + "lunch text,"
                    + "dinner text,"
                    + "happy text,"
                    + "other text,"
                    + "spare text)";
            
            //方便創建實例,簡化構造方法,方法內調用4參數構造方法
            //參數 name 可以是 數據庫名稱,也可以數據庫文件路徑(即可以指定數據庫文件路徑)
            public MySQLiteHelper(Context context, String name) {
                this(context, name, null, DATABASE_VERSION);
            }
            //必須要實現的方法
            public MySQLiteHelper(Context context, String name, CursorFactory factory, int version) {
                super(context, name, factory, version);
            }
    
            @Override
            public void onCreate(SQLiteDatabase db) {
                // 第一次創建數據庫時 纔會調用
                Log.e("mylog", "創建數據庫表");
                db.execSQL(CREATE_TABLE);
            }
    
            @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            }
            
        }
}

根據上述代碼,便獲得db對象,通過db(SQLiteDatabase)可進行數據庫的操作,如 db.query() db.delete()

如果我們想在創建一個數據庫表,參照上述代碼,可以在SQLiteOpenHelper的onCreate方法中加入語句:

@Override
public void onCreate(SQLiteDatebase db) {
    db.execSQL(CREATE_TABLE);
    db.execSQL(CREATE_BOOK);  //新創建一個數據庫表
}

然後重新運行一下,發現並沒有創建成功,因爲KogBill.db數據庫已經存在,所以MySQLiteHelper 中的onCreate方法都不會執行,解決這個辦法的方法很簡單,只需要將db文件刪除,重新運行,便可成功,但是原來數據庫中的數據都會被刪除。所以需要用到MySQLiteHelper中的update方法。

class MySQLiteHelper extends SQLiteOpenHelper{
    .....
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
        db.execSQL("drop table if exists book");  //如果已經存在就刪除,防止重複創建
        onCreate(db);  // 再次執行onCreate 方法
    }
}

但是onUpgrade方法默認是不執行的,如何讓onUpgrade方法執行,需要用到MySQLiteHelper 構造參數中的版本號:

private static final int DATABASE_VERSION = 1;//  將版本號 由 1 改爲2 

這裏將數據庫版本號由1改爲2,表示對數據庫的升級

數據庫的增刪改查

添加數據

ContentValues values = new ContentValues();
    values.put("date", str1.isEmpty()?"0.0":str1);
    values.put("breakfast", ""+str2);
    values.put("lunch", ""+str3);
    values.put("dinner", ""+str4);
    values.put("happy", ""+str5);
    values.put("other", ""+str6);
    values.put("spare", ""+str7);
    long ii = db.insert("kog_bill", "", values);
    values.clear();
    if(ii != -1) {
        Utils.showToast("保存成功!", MainActivity.this);
    }else {
        Utils.showToast("保存失敗!", MainActivity.this);
    }

更新數據

ContentValues valus = new ContentValues();
valuse.put("other","12");
db.update("kogBill", values, "_id=?",new String[]{id});

刪除數據

db.delete("kogBill", "_id=?",new String[]{id});

查詢數據

db.query("kog_bill", new String[]{"_id","date","breakfast","lunch","dinner","happy","other","spare"}
        , null, null, null, null, "date desc");

使用SQL操作數據庫
雖然Android 已經給我們提供了非常方便的API用於操作數據庫,不過總會有些人不習慣去使用這些輔助行的方法,而是更加青睞於直接使用SQL來操作數據庫,當然Android也是提供的。

添加數據

db.execSQL("insert into kogBill ("date","breakfest","lunch","dinner","happy","other","spare") values (?,?,?,?,?,?,?)", new String[]{"1921-1-1",“123”,“1”,“1”,“11”,“2”,“3”});

更新數據

db.execSQL("update kogBill set other = ? where _id = ? ", new String[]{"12",id});

刪除數據

db.execSQL("delete from kogBill where _id = ?”, new String[]{id});

使用 LitePal 操作數據庫

假設編譯環境爲AndroidStudio。

1,引進包

dependencies{
    compile fileTree(dir:'libs', include:['*.jar'])
    compile 'com.android.support:appcompat-v7:23.2.0'
    testCompile 'junt:junt:4.12'
    compile 'org.litepal.android:core:1.3.2'   //引入litepal包
}

2,配置litepal.xml 文件

右鍵app/src/main 目錄->New -> Directory ,創建一個assets目錄,然後在 assets目錄下再新建一個litepal.xml 文件,接着編輯文件中的內容

<?xml version='1.0' encoding="utf-8"?>
<litepal>
    <dbname value = "BookStore"></dbname>
    <version value="1"></version>
    <list></list>
</listepal>

其中,<dbname 標籤用來指定數據庫名,<version 用來指定數據庫版本號,<list 標籤用來指定所有映射模型。
最後還需要在配置以下 LitePalApplication, 修改AndroidManifest.xml 中的代碼

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.litepaltest" >
    <application
        android:name="org.litepal.LitePalApplication"  //配置 LitePalApplication
        android:allowBackup="true"
        .....
    </application>
</manifest>

以上,LitePal的配置工作已經結束了,接下來使用LitePal。

首先將需要實現 javabean類 對應 數據庫表.
然後將javabean類添加到映射模型列表中,修改litepal.xml 中的代碼

<litepal>
    <dbname value="kogBill" ></dbname>
    <version value="1"></version>
    <list>
        <mapping class="com.example.litepaltest.book"></mapping>  //javabean類的路徑
    </list>

這樣所有工作就已經完成,現在只要進行任意一次數據庫的操作,數據庫db文件就會自動創建,比如:

Connector.getDatabase();

操作數據

如果需要對某個表進行數據操作,需要讓其對應的javaBean類繼承DataSupport

public class Book extends DataSupport { //讓對應的類繼承DataSupport
    ...
}

接下來,進行添加數據的操作:

Book book = new Book();
book.setName("...");
book.setAuthor("...");
book.setPages(234);
book.setPrice(12,21);
book.setPress("unkow");
book.save();  //執行sava 就可以插入數據了

執行更新數據:

Book book = new Book();
book.setPrice(11.11);
book.setPress("Anchor");
book.updateAll("name = ?  and authro = ?","..","...");

刪除數據:

DataSupport.deleteAll(Book.class, "price<?","13");

查詢數據:

//查詢所有
List<Book> books = DataSupport.findAll(Book.class);  
// 查詢第一條
List<Book> books = DataSupport.findFirst(Book.class);
//查詢最後一條
List<Book> books = DataSupport.findLast(Book.class);
//查詢那幾列的數據
List<Book> books = DataSupport.select("name","author).find(Book.class);
//條件查詢, 頁面大於400
List<Book> books = DataSupport.where("pages >?","400").find(Book.class);
//將 price 降序排序
List<Book> books = DataSupport.order(price desc").find(Book.class);
//查詢前3條
List<Book> books = DataSupport.limit(3).find(Book.class);
//從下表1開始,往後查詢3條
List<Book> boods = DataSupport.limit(3).offset(1),find(Book.class)

當然這些方法也可以組合起來使用:

List<Book> books = DataSupport.select("name","author","pages")
                                                            .where("pages>?”,"400")
                                                            .order("pages")
                                                            .limit(10)
                                                            .offset(10)
                                                            .find(Book.class);

如果有些特殊查詢,使用上述方法無法查詢時,可以使用如下語句:

Cursor c  = DataSupport.findBySQL("select * from Book where pages > ? and price < ?”, 
        "400","20”);

內容提供器(Conent Provider)方式

網絡存儲方式

Android 六大布局

LinearLayout 線性佈局

線性佈局,如名字所描述的那樣,這個佈局將它所包含的控件在線性方向上一次排列,方向分爲 水平方向和數值方向。

屬性 android:orientation = “vertical” | “horizontal” 豎直或水平,默認水平
屬性 android:layout_gravity = “top” | “center” | “bottom” 內部的佈局方式
屬性 android:gravity = “top”|"center”|“bottom” 相對於父容器的對齊方式
屬性 android:layout_weidht 使用比例方式執行控件的大小,在手機屏幕適配方面起到非常重要的作用

TableLayout 表格佈局

表格佈局與HTML中的table td tr標籤類似

<table>
    <tr><td></td></tr>
</table>

如何確定行與列

如果在TableLayout下添加組件,這個組件會佔滿整行

如果想把多個組件放在同一行,需要添加TableRow的容器,然後把組件放進去
TableRow中的組件個數決定的該行的列數,而列的寬度由列中最寬的單元格決定
TableRow嗯layout_width屬性默認是fill-parent,修改無效。但是layout_height默認是wrapcontent,可以修改
整個表格的寬度取決於父容器的寬度(佔滿父容器)
重要的屬性:

android:collapaseColumns:設置需要被隱藏的列的序號
android:shrinkColumns:設置允許被收縮的列的序號
android:stretchCoumns:設置運行被拉伸嗯列的序號
這三個屬性都是從0開始算的

shrinkColumns= "2" //對應第三行
shrinkColumns = '"0,2" //設置多個都生效
shrinkColumns = "" //所有列都生效

android:layout_column=“2”: 表示跳過第二個,直接顯示第三個,從1開始
android:layout_span=“4”:表示合併*4個單元格,也就說這個組件佔4個單元格

FrameLayout 幀佈局

FrameLayout佈局在不使用layout_gravity屬性的情況下,佈局中的多項元素會在父容器的左上角重疊,使用layout_gravity 屬性,可以設置不同的位置。

重要屬性

  • top、bottom、left、right:將對象放在其容器的上、下、左、右的位置
  • center、center_vertical、center_horizontal:講對象居中、水平居中、豎直居中

注意 :區分 “android:gravity” 和 “android:layout_gravity”
android:gravity :是對控件本身而言,控制控件自身的內容在控件中的位置
android:layout_gravity:是相對於控件父容器而言,設置該控件在其父容器中的位置
RelativeLayout 相對佈局
相對佈局是用的比較多的一種佈局。因爲佈局套用越多,佈局加載越慢,如果使用相對佈局,緊緊只需要一次佈局。一般使用佈局都是相對佈局+線性佈局使用。
相對佈局主要記住重要的屬性

此圖來自:https://www.runoob.com/w3cnote/android-tutorial-relativelayout.html

注意:margin 和 padding 的區別

  • margin:代表的是偏移,是相對於父容器而言
  • padding:代表的是填充,是本組件內部而言

GridLayout 網格佈局
網格佈局與TableLayout(表格佈局)類似,不過網格佈局功能更多,也更好用。

可以設置佈局中組件的排列方式
可以設置網格佈局有幾行幾列
可以直接設置組件的位置,位於某行某列
可以直接設置組件佔多少行多少列
使用網格佈局,需要先設置排列方式、對齊方式、行數、列數。然後對佈局中的子組件進行行列設置。

圖片來自:https://blog.csdn.net/wangmx1993328/article/details/82770910

下例是計算器佈局:

<GridLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:columnCount="4"
        android:orientation="horizontal"
        android:rowCount="6">
        <TextView
            android:layout_columnSpan="4"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:background="#ffcccccc"
            android:text="0"
            android:textSize="50sp"
            android:layout_gravity="fill" />
        <Button
            android:layout_columnSpan="1"
            android:text="1"
            android:layout_gravity="fill" />
        <Button
            android:text="2"
            android:layout_gravity="fill" />
        <Button
            android:text="3"
            android:layout_gravity="fill" />
        <Button
            android:text="+"
            android:layout_gravity="fill" />

        <Button
            android:layout_columnSpan="1"
            android:text="4"
            android:layout_gravity="fill" />
        <Button
            android:text="5"
            android:layout_gravity="fill" />
        <Button
            android:text="6"
            android:layout_gravity="fill" />
        <Button
            android:text="-"
            android:layout_gravity="fill" />
        <Button
            android:layout_columnSpan="1"
            android:text="7"
            android:layout_gravity="fill" />
        <Button
            android:text="8"
            android:layout_gravity="fill" />
        <Button
            android:text="9"
            android:layout_gravity="fill" />
        <Button
            android:text="*"
            android:layout_gravity="fill" />
        <Button
            android:layout_columnSpan="1"
            android:text=""
            android:layout_gravity="fill" />
        <Button
            android:text="0"
            android:layout_gravity="fill" />
        <Button
            android:text="="
            android:layout_gravity="fill" />
        <Button
            android:text="/"
            android:layout_gravity="fill" />
    </GridLayout>

AbsoluteLayout 絕對佈局

絕對佈局放在最後,是因爲絕對佈局基本上是不使用的。一般佈局需要適配不同機型,如果使用絕對佈局,在不同尺寸的手機上顯示會變形。

重要屬性

android:layout_x:設置組件的x座標
android:layout_y:設置組件的y座標

<AbsoluteLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_x="50dp"
            android:layout_y="100dp"
            android:text="=" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_x="150dp"
            android:layout_y="100dp"
            android:text="=" />

        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_x="100dp"
            android:layout_y="120dp"
            android:text="." />

    </AbsoluteLayout>

最後

今天就帶大家學到這裏,需要Android架構完整學習資料的朋友可以【直接點擊此處】去文件夾取,免費分享大家。

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