2019-05-26

Android 四大組件,五大存儲搂漠,六大布局

一、Android 四大組件

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

一靶壮、Activity

1怔毛、概念:

android 中,Activity 相當(dāng)于一個頁面腾降,可以在Activity中添加Button拣度、CheckBox 等控件,一個android 程序有多個Activity組成螃壤。

2抗果、生命周期:
Activity.jpg

3、四中啟動模式

Standard 模式 : standard 模式是android 的默認啟動模式奸晴,在這種模式下冤馏,activity可以有多個實例,每次啟動Activity寄啼,無論任務(wù)棧中是否已經(jīng)存在這個activity的實例逮光,系統(tǒng)都會創(chuàng)建一個新的activity實例赘淮。

SingleTop 模式: 棧頂模式,當(dāng)一個singleTop模式的activity 已經(jīng)位于棧頂時睦霎,再去啟動它時梢卸,不在創(chuàng)建實例,如果不在棧頂副女,就會創(chuàng)建實例蛤高。

SingleTask 模式 : 單任務(wù)模式,如果啟動的activity 已經(jīng)存在于 任務(wù)棧中碑幅,則會將activity移動到棧頂戴陡,并將上面的activity出棧,否則創(chuàng)建新的實例

SingleInstance 模式 :單實例模式沟涨,一個activity 一個棧恤批。

4、三種跳轉(zhuǎn)方式

顯示啟動 :
Intrent 內(nèi)部直接聲明要啟動的activity所對應(yīng)的的class

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

隱式啟動
進行三個匹配裹赴,一個是activity喜庞,一個是category,一個是data棋返,全部或者部分匹配延都,應(yīng)用于廣播原理

清單文件中 里配置activity屬性,activity的名字要和跳轉(zhuǎn)內(nèi)容一樣

   <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>

在需要跳轉(zhuǎn)的地方

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

跳轉(zhuǎn)后再返回睛竣,能獲取返回值

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

在OTherActivity中設(shè)置返回值

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

項目內(nèi)Server包 右鍵 --> New --> Service --> Service 或者直接創(chuàng)建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() 方法在服務(wù)創(chuàng)建的時候調(diào)用殊者、onStartCommand() 方法會在每次服務(wù)啟動的時候調(diào)用、onDestory() 方法會在服務(wù)銷毀的時候調(diào)用验夯。
通常情況下猖吴,如果我們希望服務(wù)一旦啟動就立刻去執(zhí)行任務(wù),就可以將邏輯卸載onStartCommand() 方法里簿姨。
另外需要注意的是距误,每個服務(wù)都需要在Androidmanifest.xml 中進行注冊才能生效:

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

啟動和停止服務(wù)

啟動服務(wù):

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

停止服務(wù):

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

使用前臺服務(wù)

前臺服務(wù)與普通服務(wù)的最大區(qū)別在于,它會一直有一個正在運行的圖標(biāo)在系統(tǒng)的狀態(tài)欄中扁位,下拉狀態(tài)欄后可以看到更加詳細的內(nèi)容准潭,非常類似于通知的效果。

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);
}

構(gòu)造一個Notification對象后并沒有使用NotificationManager 來講通知顯示出來域仇,而是調(diào)用了startForeground()方法刑然,該方法會將MyService變成一個前臺服務(wù),并在系統(tǒng)狀態(tài)欄中顯示出來暇务。

使用IntentService

服務(wù)中的代碼都默認運行在主線程中泼掠,如果直接在服務(wù)中執(zhí)行耗時操作很容易出現(xiàn)ANR(Application not Responding)
所以這個時候需要用到Android多線程編程技術(shù)怔软,我們應(yīng)該在服務(wù)的每個具體的方法里啟動一個子線程,然后在這里去處理那些耗時的操作:

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);
    }
}

但是择镇,這種服務(wù)一旦啟動之后挡逼,就會一直處于運行狀態(tài),必須調(diào)用stopService()或者stopSelf()方法才能讓服務(wù)停止下來腻豌,所以家坎,如果想要實現(xiàn)讓一個服務(wù)在執(zhí)行完畢后自動停止的功能,就可以這樣寫:

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

雖說這樣的寫法并不復(fù)雜吝梅,但是總會有一些程序員忘記開啟線程或者忘記調(diào)用stopSelf() 方法虱疏。為了簡單創(chuàng)建一個異步、會自動停止的服務(wù)苏携。Android專門提供了一個IntentService類

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

首先這里提供一個無參的構(gòu)造方法做瞪,并且必須在其內(nèi)部調(diào)用父類的有參構(gòu)造方法。然后要在子類中去實現(xiàn)onHandleIntent() 這個抽象方法右冻,在這個方法中可以去處理一些邏輯装蓬,而且不用擔(dān)心ANR,因為這個方法已經(jīng)是在子線程中運行了国旷。
IntentService線程的調(diào)用:

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

如此矛物,線程就會自動啟動并執(zhí)行邏輯,執(zhí)行完畢后自動關(guān)閉跪但。這就是IntentService 的好處,能夠自動開啟和關(guān)閉峦萎;

Content Provider

對于每一個應(yīng)用程序來說屡久,如果想要訪問內(nèi)容提供器中共享的數(shù)據(jù),就一定要借助ContentResolver 類爱榔,可以通過Context中的getContentResolver() 方法獲取該類的實例被环。ContentResolver中提供了一系列的方法用于對數(shù)據(jù)進行CRUD操作,其中insert() 方法用于添加數(shù)據(jù)详幽,update() 方法用于更新數(shù)據(jù)筛欢,delete() 方法用于刪除數(shù)據(jù),query() 方法用于查詢數(shù)據(jù)唇聘。
不同于SQLiteDatabase版姑,ContentResolver 中的增刪改查都是接收一個URl參數(shù),這個參數(shù)被稱為內(nèi)容URL迟郎。內(nèi)容URL給內(nèi)容提供器中的數(shù)據(jù)建立了唯一標(biāo)識符剥险,它主要由兩部分組成:authority 和 path 。authority 是用于對不同的應(yīng)用程序做區(qū)分的宪肖,一般為了避免沖突表制,都會采用程序包名的方式進行命名健爬。path則是用于對同一應(yīng)用程序中不同的表做區(qū)分,通常都會添加到authority后面:

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

在使用內(nèi)容URL作為參數(shù)的時候么介,需要將URL轉(zhuǎn)換成URL對象:

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

現(xiàn)在我們就可以使用這個uri對象來查詢talbe1表中的數(shù)據(jù)了:

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

對應(yīng)參數(shù)的解釋:

query()方法參數(shù) 對應(yīng)SQL部分 描述
uri from table_name 指定查詢某個應(yīng)用程序下的某個表
projection  select column1, column2 指定查詢的列名
selection   where column=value  指定where約束條件
selectArgs  -   為where中的占位符提供具體的值
orderBy order by column1, column2   指定查詢結(jié)果的排序方式

查詢完之后娜遵,就可以從游標(biāo)中取值了:

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

增刪改查

添加數(shù)據(jù)

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

更新數(shù)據(jù)

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

刪除數(shù)據(jù)

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

實例.

讀取系統(tǒng)聯(lián)系人
讀取系統(tǒng)聯(lián)系人需要聲明權(quán)限,如果系統(tǒng)是6.0以后的壤短,需要申請運行時權(quán)限

if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) 
    != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
    }else {
        readContacts();  //讀取聯(lián)系人
    }
private void readContacts(){
    Cursor cursor = null;
    try{
        //查詢聯(lián)系人數(shù)據(jù)
        cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);
        if(cursor!=null){
            while(cursor.moveToNext()){
                //獲取聯(lián)系人姓名
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                //獲取聯(lián)系人電話號碼
                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 {
                //您拒絕了權(quán)限
            }
    }
}

創(chuàng)建自己的內(nèi)容提供器

創(chuàng)建自己的內(nèi)容提供器魔熏,需要去繼承 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

* : 表示匹配任意長度的任意字符
# : 表示匹配任意長度的數(shù)字

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

Broadcast Receiver

android 廣播分為兩個角色:廣播發(fā)送者躲雅、廣播接收者
android 廣播:
1),用于不同組件間的通信(含:應(yīng)用內(nèi)/不同應(yīng)用之間)
2)骡和,用于多線程通信
3)相赁,與android系統(tǒng)的通信

自定義廣播接收者

繼承BroadcastReceive 基類
必須重寫抽象方法onReceive()方法
1,廣播接收器收到相應(yīng)廣播后慰于,會自動調(diào)用onReceive() 方法
2钮科,一般情況下,onReceive方法會會涉及與其他組件之間的交互婆赠,如 發(fā)送Notiotification绵脯,啟動server等
3,默認情況下休里,廣播接收器運行在UI線程蛆挫,因此,onReceive方法不能執(zhí)行耗時操作妙黍,否則將導(dǎo)致ANR

廣播接收器注冊

注冊的方式有兩種:靜態(tài)注冊悴侵、動態(tài)注冊
靜態(tài)注冊

注冊方式:在AndroidManifest.xml 里通過<receive 標(biāo)簽聲明
屬性說明

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

//用于指定此廣播接收器將接收的廣播類型
//本示例中給出的是用于接收網(wǎng)絡(luò)狀態(tài)改變時發(fā)出的廣播
 <intent-filter>
    <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
 </intent-filter>
 </receiver>

注冊示例:

<receiver 
    //此廣播接收者類是mBroadcastReceiver
    android:name=".mBroadcastReceiver" >
    //用于接收網(wǎng)絡(luò)狀態(tài)改變時發(fā)出的廣播
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

當(dāng)此APP首次啟動時浇借,系統(tǒng)會自動實例化mBroadcastReceiver類,并注冊到系統(tǒng)中驮宴。

動態(tài)注冊

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

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

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

    // 3. 動態(tài)注冊:調(diào)用Context的registerReceiver()方法
     registerReceiver(mBroadcastReceiver, intentFilter);


//動態(tài)注冊廣播后逮刨,需要在相應(yīng)位置記得銷毀廣播
unregisterReceiver(mBroadcastReceiver);

特別注意
動態(tài)廣播最好在onResume中注冊, onPause注銷
原因:
1,對于動態(tài)廣播修己,有注冊必然得有注銷恢总,否則會導(dǎo)致內(nèi)存泄漏
2,onPause在App死亡前一定會被執(zhí)行睬愤,從而保證app死亡前一定會被注銷片仿,從而防止內(nèi)存泄漏

兩種注冊方式的區(qū)別
廣播的發(fā)送
廣播的發(fā)送 = 廣播發(fā)送者 將此廣播的意圖(intent)通過 sendBroasdcast() 方法發(fā)送出去
廣播的類型

普通廣播 系統(tǒng)廣播 有序廣播 粘性廣播 App 應(yīng)用內(nèi)廣播
特別注意:

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

對于靜態(tài)注冊(全局+應(yīng)用內(nèi)廣播)尤辱,回調(diào)onReceive(context,
intent)中的context返回值是:ReceiverRestrictedContext砂豌;
對于全局廣播的動態(tài)注冊,回調(diào)onReceive(context, intent)中的context返回值是:Activity
Context光督;
對于應(yīng)用內(nèi)廣播的動態(tài)注冊(LocalBroadcastManager方式)阳距,回調(diào)onReceive(context,
intent)中的context返回值是:Application Context。
對于應(yīng)用內(nèi)廣播的動態(tài)注冊(非LocalBroadcastManager方式)结借,回調(diào)onReceive(context,
intent)中的context返回值是:Activity Context筐摘;

Android 五大存儲

SharedPreferences 方式

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

//此方法接收兩個參數(shù)柳畔,一個參數(shù)用于指定SharedPreferences文件的名稱馍管,如果指定的文件不存在則會創(chuàng)建一個,SharedPreferences文件都是存放在/data/data/<package name>/shared_prefs/目錄下
//第二個參數(shù)用于指定操作模式薪韩,目前只有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()方法很類似躬存,不過它只接收一個操作模式张惹,因為使用這個方法時會自動將當(dāng)前活動的類名作為SharedPreferences的文件名
3,PreferencesManager類中的getDefaultSharedPreferences()方法

//這是一個靜態(tài)方法岭洲,它接收一個Context參數(shù),并自動使用當(dāng)前應(yīng)用程序的包名作為前綴來命名SharedPreferences文件
得到了SharedPreferences對象后坎匿, 就可以開始想SharedPreferences文件中存儲數(shù)據(jù)了盾剩,主要可以分為三步:
(1)調(diào)用SharedPreferences對象的edit()方法來獲取一個SharedPreferences.Editor對象
(2)向SharedPreferences.Editor 對象中添加數(shù)據(jù),比如添加一個布爾值替蔬,可以使用putBoolean() 方法
(3)調(diào)用apply()方法的添加的數(shù)據(jù)提交告私,從而完成數(shù)據(jù)存儲操作

SharedPreferences中讀取數(shù)據(jù)

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 為了讓我們能夠更加方便的管理數(shù)據(jù)庫,專門提供了一個SQLiteOpenHelper 幫助類承桥,借助這個類可以非常簡單的將數(shù)據(jù)庫進行創(chuàng)建好升級驻粟。
SQLiteOpenHelper 中有兩個非常重要的實例方法,getReadableDatabase() 和 getWritableDatabase() 。這兩個方法可以創(chuàng)建或者打開一個現(xiàn)有的數(shù)據(jù)庫(如果數(shù)據(jù)庫存在則直接打開蜀撑,否則創(chuàng)建一個新的數(shù)據(jù)庫)挤巡,并返回一個可對數(shù)據(jù)庫進行讀寫操作的對象。不同的是酷麦,當(dāng)數(shù)據(jù)庫不可寫入(如磁盤空間已滿)矿卑,getReadableDatabase方法返回的對象將以只讀的方式打開數(shù)據(jù)庫,而getWeitableDatabase則出現(xiàn)異常

例子(在指定路徑下創(chuàng)建數(shù)據(jù)庫文件 .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 沃饶,該對象可以操作數(shù)據(jù)庫

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

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

    class MySQLiteHelper extends SQLiteOpenHelper{
            private static final int DATABASE_VERSION = 1;//數(shù)據(jù)庫版本號
            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)";
            
            //方便創(chuàng)建實例糊肤,簡化構(gòu)造方法琴昆,方法內(nèi)調(diào)用4參數(shù)構(gòu)造方法
            //參數(shù) name 可以是 數(shù)據(jù)庫名稱,也可以數(shù)據(jù)庫文件路徑(即可以指定數(shù)據(jù)庫文件路徑)
            public MySQLiteHelper(Context context, String name) {
                this(context, name, null, DATABASE_VERSION);
            }
            //必須要實現(xiàn)的方法
            public MySQLiteHelper(Context context, String name, CursorFactory factory, int version) {
                super(context, name, factory, version);
            }
    
            @Override
            public void onCreate(SQLiteDatabase db) {
                // 第一次創(chuàng)建數(shù)據(jù)庫時 才會調(diào)用
                Log.e("mylog", "創(chuàng)建數(shù)據(jù)庫表");
                db.execSQL(CREATE_TABLE);
            }
    
            @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            }
            
        }
}

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

如果我們想在創(chuàng)建一個數(shù)據(jù)庫表把介,參照上述代碼勤讽,可以在SQLiteOpenHelper的onCreate方法中加入語句:

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

然后重新運行一下,發(fā)現(xiàn)并沒有創(chuàng)建成功拗踢,因為KogBill.db數(shù)據(jù)庫已經(jīng)存在脚牍,所以MySQLiteHelper 中的onCreate方法都不會執(zhí)行,解決這個辦法的方法很簡單巢墅,只需要將db文件刪除诸狭,重新運行,便可成功君纫,但是原來數(shù)據(jù)庫中的數(shù)據(jù)都會被刪除驯遇。所以需要用到MySQLiteHelper中的update方法。

class MySQLiteHelper extends SQLiteOpenHelper{
    ```
verride
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
        db.execSQL("drop table if exists book");  //如果已經(jīng)存在就刪除蓄髓,防止重復(fù)創(chuàng)建
        onCreate(db);  // 再次執(zhí)行onCreate 方法
    }
}

但是onUpgrade方法默認是不執(zhí)行的叉庐,如何讓onUpgrade方法執(zhí)行,需要用到MySQLiteHelper 構(gòu)造參數(shù)中的版本號:

private static final int DATABASE_VERSION = 1;// 將版本號 由 1 改為2
這里將數(shù)據(jù)庫版本號由1改為2会喝,表示對數(shù)據(jù)庫的升級

數(shù)據(jù)庫的增刪改查

添加數(shù)據(jù)

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);
    }

更新數(shù)據(jù)

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

刪除數(shù)據(jù)

db.delete("kogBill", "_id=?",new String[]{id});
查詢數(shù)據(jù)

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

使用SQL操作數(shù)據(jù)庫

雖然Android 已經(jīng)給我們提供了非常方便的API用于操作數(shù)據(jù)庫,不過總會有些人不習(xí)慣去使用這些輔助行的方法预茄,而是更加青睞于直接使用SQL來操作數(shù)據(jù)庫兴溜,當(dāng)然Android也是提供的。
添加數(shù)據(jù)

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

更新數(shù)據(jù)

db.execSQL("update kogBill set other = ? where _id = ? ", new String[]{"12",id});
刪除數(shù)據(jù)

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

使用 LitePal 操作數(shù)據(jù)庫

假設(shè)編譯環(huán)境為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 ,創(chuàng)建一個assets目錄,然后在 assets目錄下再新建一個litepal.xml 文件鹉梨,接著編輯文件中的內(nèi)容

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

其中,<dbname 標(biāo)簽用來指定數(shù)據(jù)庫名存皂,<version 用來指定數(shù)據(jù)庫版本號晌坤,<list 標(biāo)簽用來指定所有映射模型。
最后還需要在配置以下 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的配置工作已經(jīng)結(jié)束了骤菠,接下來使用LitePal。
首先將需要實現(xiàn) javabean類 對應(yīng) 數(shù)據(jù)庫表.
然后將javabean類添加到映射模型列表中疤孕,修改litepal.xml 中的代碼

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

這樣所有工作就已經(jīng)完成商乎,現(xiàn)在只要進行任意一次數(shù)據(jù)庫的操作,數(shù)據(jù)庫db文件就會自動創(chuàng)建祭阀,比如:

Connector.getDatabase();
操作數(shù)據(jù)

如果需要對某個表進行數(shù)據(jù)操作鹉戚,需要讓其對應(yīng)的javaBean類繼承DataSupport

public class Book extends DataSupport { //讓對應(yīng)的類繼承DataSupport
    ...
}

接下來,進行添加數(shù)據(jù)的操作:

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

執(zhí)行更新數(shù)據(jù):

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

刪除數(shù)據(jù):

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

查詢數(shù)據(jù):

//查詢所有
List<Book> books = DataSupport.findAll(Book.class);  
// 查詢第一條
List<Book> books = DataSupport.findFirst(Book.class);
//查詢最后一條
List<Book> books = DataSupport.findLast(Book.class);
//查詢那幾列的數(shù)據(jù)
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)

當(dāng)然這些方法也可以組合起來使用:

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”);

內(nèi)容提供器(Conent Provider)方式

網(wǎng)絡(luò)存儲方式

Android 六大布局

LinearLayout 線性布局

線性布局,如名字所描述的那樣柏蘑,這個布局將它所包含的控件在線性方向上一次排列颖系,方向分為 水平方向和數(shù)值方向。
屬性 android:orientation = “vertical” | “horizontal” 豎直或水平辩越,默認水平
屬性 android:layout_gravity = “top” | “center” | “bottom” 內(nèi)部的布局方式
屬性 android:gravity = “top”|"center”|“bottom” 相對于父容器的對齊方式
屬性 android:layout_weidht 使用比例方式執(zhí)行控件的大小,在手機屏幕適配方面起到非常重要的作用

TableLayout 表格布局

FrameLayout 幀布局

RelativeLayout 相對布局

GridLayout 網(wǎng)格布局

AbsoluteLayout 絕對布局

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末信粮,一起剝皮案震驚了整個濱河市黔攒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌阿逃,老刑警劉巖孽尽,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件延欠,死亡現(xiàn)場離奇詭異藕咏,居然都是意外死亡烘豹,警方通過查閱死者的電腦和手機邓萨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門又固,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怀酷,“玉大人觉阅,你說我怎么就攤上這事崖疤。” “怎么了典勇?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵劫哼,是天一觀的道長。 經(jīng)常有香客問我割笙,道長权烧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任伤溉,我火速辦了婚禮般码,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘乱顾。我一直安慰自己板祝,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布糯耍。 她就那樣靜靜地躺著扔字,像睡著了一般。 火紅的嫁衣襯著肌膚如雪温技。 梳的紋絲不亂的頭發(fā)上革为,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天,我揣著相機與錄音舵鳞,去河邊找鬼震檩。 笑死,一個胖子當(dāng)著我的面吹牛蜓堕,可吹牛的內(nèi)容都是我干的抛虏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼套才,長吁一口氣:“原來是場噩夢啊……” “哼迂猴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起背伴,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤沸毁,失蹤者是張志新(化名)和其女友劉穎峰髓,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體息尺,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡携兵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了搂誉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徐紧。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖炭懊,靈堂內(nèi)的尸體忽然破棺而出并级,到底是詐尸還是另有隱情,我是刑警寧澤凛虽,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布死遭,位于F島的核電站,受9級特大地震影響凯旋,放射性物質(zhì)發(fā)生泄漏呀潭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一至非、第九天 我趴在偏房一處隱蔽的房頂上張望钠署。 院中可真熱鬧,春花似錦荒椭、人聲如沸谐鼎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狸棍。三九已至,卻和暖如春味悄,著一層夾襖步出監(jiān)牢的瞬間草戈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工侍瑟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留唐片,地道東北人。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓涨颜,卻偏偏與公主長得像费韭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子庭瑰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 2.1 Activity 2.1.1 Activity的生命周期全面分析 典型情況下的生命周期:在用戶參與的情況下...
    AndroidMaster閱讀 3,031評論 0 8
  • 2018年Android 面試題 IT開發(fā)仔2018-03-21 15:26:46 在這“金三銀四”的季節(jié)星持,我準(zhǔn)備...
    王培921223閱讀 2,511評論 3 24
  • 面試題總結(jié) 通用 安卓學(xué)習(xí)途徑, 尋找資料學(xué)習(xí)的博客網(wǎng)站 AndroidStudio使用, 插件使用 安卓和蘋果的...
    JingBeibei閱讀 1,658評論 2 21
  • 去年钉汗,歐洲因暴風(fēng)雪來襲羹令,天氣的劇烈變化使得很多流浪動物因此喪命。令人感動的是在土耳其损痰,一位名叫巴幼(Bayal)的...
    在日留學(xué)生活閱讀 678評論 0 0
  • 鷹大大,有點壯...... 可以解釋為酒来,那是它厚厚的羽毛卢未,為了防寒。 嗯堰汉,這個解釋不錯辽社,哈哈哈哈哈...... 山...
    文樸閱讀 900評論 10 14