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架構完整學習資料的朋友可以【直接點擊此處】去文件夾取,免費分享大家。