Android 四大組件,五大存儲搂漠,六大布局
一、Android 四大組件
android四大組件分別是:Activity某弦, service桐汤,content provider,broadcast receiver
一靶壮、Activity
1怔毛、概念:
android 中,Activity 相當(dāng)于一個頁面腾降,可以在Activity中添加Button拣度、CheckBox 等控件,一個android 程序有多個Activity組成螃壤。
2抗果、生命周期:
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 絕對布局