Android面試,給正在找工作的安卓攻城師們 ... ...
從java基礎技能到安卓進階技能,有你想象不到的全面。
☆ JAVA技能
« 有良好的JAVA基礎,熟練掌握面向物件思想:
理解面向物件:
面向物件是一種思想,是基於面向過程而言的,就是說面向物件是將功能等通過物件來實現,將功能封裝進物件之中,讓物件去實現具體的細節;這種思想是將資料作為第一位,而方法或者說是演算法作為其次,這是對資料一種優化,操作起來更加的方便,簡化了過程。面向物件有三大特徵:封裝性、繼承性、多型性,其中封裝性指的是隱藏了物件的屬性和實現細節,僅對外提供公共的訪問方式,這樣就隔離了具體的變化,便於使用,提高了複用性和安全性。對於繼承性,就是兩種事物間存在著一定的所屬關係,那麼繼承的類就可以從被繼承的類中獲得一些屬性和方法;這就 提高了程式碼的複用性。繼承是作為多型的前提的。多型是說父類或介面的引用指向了子類對A象,這就提高了程式的擴充套件性,也就是說只要實現或繼承了同一個介面或類,那麼就可以使用父類中相應的方法,提高程式擴充套件性,但是多型有一點不好之處在於:父類引用不能訪問子類中的成員。
舉例來說:就是:比如說你要去飯店吃飯,你只需要飯店,找到飯店的服務員,跟她說你要吃什麼,然後叫會給你做出來讓你吃,你並不需要知道這個飯是怎麼錯的,你只需要面向這個服務員,告訴他你要吃什麼,然後他也只需要面向你吃完收到錢就好,不需要知道你怎麼對這個飯進行吃。
1、特點:
1:將複雜的事情簡單化。
2:面向物件將以前的過程中的執行者,變成了指揮者。
3:面向物件這種思想是符合現在人們思考習慣的一種思想。
2、面向物件的三大特徵:封裝,繼承、多型
1.封裝:只隱藏物件的屬性和實現細節,僅對外提供公共訪問方式
好處:將變化隔離、便於使用、提高複用性、提高安全性
原則:將不需要對外提供的內容隱藏起來;把屬性隱藏,提供公共方法對其訪問
2.繼承:提高程式碼複用性;繼承是多型的前提
注:
①子類中所有的建構函式都會預設訪問父類中的空引數的建構函式,預設第一行有super();若無空引數建構函式,子類中需指定;另外,子類建構函式中可自己用this指定自身的其他建構函式。
3.多型
是父類或介面定義的引用變數可以指向子類或具體實現類的例項物件
好處:提高了程式的擴充套件性
弊端:當父類引用指向子類物件時,雖提高了擴充套件性,但只能訪問父類中具備的方法,不可訪問子類中的方法;即訪問的侷限性。
前提:實現或繼承關係;覆寫父類方法。
« 熟練使用集合、IO流及多執行緒
一、集合:
1、特點:儲存物件;長度可變;儲存物件的型別可不同;
2、集合框架:
2)Collection
(1)List:有序的;元素可重複,有索引
(add(index,element)、add(index,Collection)、remove(index)、set(index,element)、get(index)、subList(from, to)、listIterator())
①ArrayList:底層是陣列結構,查詢快,增刪慢,不同步。
②LinkedList:底層是連結串列結構,增刪快,查詢慢,不同步
addFist();addLast() getFirst();getLast()
removeFirst();removeLast()獲取並刪除元素,無元素將拋異常:NoSuchElementException
替代的方法(JDK1.6):
offerFirst();offerLast();
peekFirst();peekLast();無元素返回null
pollFirst();pollLast();刪除並返回此元素,無元素返回null
③Vector:底層是陣列結構,執行緒同步,被ArrayList取代了
注:了對於判斷是否存在,以及刪除等操作,以依賴的方法是元素的hashCode和equals方法
ArrayList判斷是否存在和刪除操作依賴的是equals方法
(2)Set:無序的,無索引,元素不可重複
①HashSet:底層是雜湊表,執行緒不同步,無序、高效
保證元素唯一性:通過元素的hashCode和equals方法。若hashCode值相同,則會判斷equals的結果是否為true;hashCode不同,不會呼叫equals方法
LinkedHashSet:有序,是HashSet的子類
②TreeSet:底層是二叉樹,可對元素進行排序,預設是自然順序
保證唯一性:Comparable介面的compareTo方法的返回值
===》TreeSet兩種排序方式:兩種方式都存在時,以比較器為主
第一種:自然排序(預設排序):
新增的物件需要實現Comparable介面,覆蓋compareTo方法
第二種:比較器
新增的元素自身不具備比較性或不是想要的比較方式。將比較器作為引數傳遞進去。
定義一個類,實現Comparator介面,覆蓋compare方法。當主要條件相同時,比較次要條件。
3)Map集合:
(1)HashTable:底層資料結構是雜湊表,不可存入null鍵和null值。同步的
Properties繼承自HashTable,可儲存在流中或從流中載入,是集合和IO流的結合產物
(2)HashMap:底層資料結構是雜湊表;允許使用null鍵和null值,不同步,效率高
TreeMap:
底層資料結構時二叉樹,不同步,可排序
與Set很像,Set底層就是使用了Map集合
方法:
V put(K key, V value); void putAll(Map m)
void clear(); V remove(Object key)
booleancontainsKey(Object key); containsValue(Object key); isEmpty()
V get(Object key); intsize(); Collection<V> values()
Set<K>keySet(); Set<Map.Entry<K,V>> entrySet()
2.3、Map集合兩種取出方式:
第一種:Set<K> keySet()
取出Map集合中的所有鍵放於Set集合中,然後再通過鍵取出對應的值
Set<String> keySet= map.keySet();
Iterator<String>it = keySet.iterator();
while(it.hasNext()){
String key = it.next();
String value = map.get(key);
//…..
}
第二種:Set<Map.Entry<K,V>> entrySet()
取出Map集合中鍵值對的對映放於Set集合中,然後通過Map集合中的內部介面,然後通過其中的方法取出
Set<Map.Entry<String,String>>entrySet = map.entrySet();
Iterator<Map.Entry<String,String>>it = entrySet.iterator();
While(it.hasNext()){
Map.Entry<String,String> entry = it.next();
String key = entry.getKey();
String value = entry.getValue();
//……
}
2.4、Collection和Map的區別:
Collection:單列集合,一次存一個元素
Map:雙列集合,一次存一對集合,兩個元素(物件)存在著對映關係
2.5、集合工具類:
Collections:操作集合(一般是list集合)的工具類。方法全為靜態的
sort(List list);對list集合進行排序;sort(List list, Comparator c) 按指定比較器排序
fill(List list, T obj);將集合元素替換為指定物件;
swap(List list, int I,int j)交換集合指定位置的元素
shuffle(List list); 隨機對集合元素排序
reverseOrder() :返回比較器,強行逆轉實現Comparable介面的物件自然順序
reverseOrder(Comparatorc):返回比較器,強行逆轉指定比較器的順序
2.6、Collection和Collections的區別:
Collections:java.util下的工具類,實現對集合的查詢、排序、替換、執行緒安全化等操作。
Collection:是java.util下的介面,是各種單列集合的父介面,實現此介面的有List和Set集合,儲存物件並對其進行操作。
3、Arrays:
用於運算元組物件的工具類,全為靜態方法
asList():將陣列轉為list集合
好處:可通過list集合的方法運算元組中的元素:
isEmpty()、contains()、indexOf()、set()
弊端:陣列長度固定,不可使用集合的增刪操作。
如果陣列中儲存的是基本資料型別,asList會將陣列整體作為一個元素存入集合
集合轉為陣列:Collection.toArray();
好處:限定了對集合中的元素進行增刪操作,只需獲取元素
二、IO流
1、結構:
位元組流:InputStream,OutputStream
字元流:Reader,Writer
Reader:讀取字元流的抽象類
BufferedReader:將字元存入緩衝區,再讀取
LineNumberReader:帶行號的字元緩衝輸入流
InputStreamReader:轉換流,位元組流和字元流的橋樑,多在編碼的地方使用
FileReader:讀取字元檔案的便捷類。
Writer:寫入字元流的抽象類
BufferedWriter:將字元存入緩衝區,再寫入
OutputStreamWriter:轉換流,位元組流和字元流的橋樑,多在編碼的地方使用
FileWriter:寫入字元檔案的便捷類。
InputStream:位元組輸入流的所有類的超類
ByteArrayInputStream:含緩衝陣列,讀取記憶體中位元組陣列的資料,未涉及流
FileInputStream:從檔案中獲取輸入位元組。媒體檔案
BufferedInputStream:帶有緩衝區的位元組輸入流
DataInputStream:資料輸入流,讀取基本資料型別的資料
ObjectInputStream:用於讀取物件的輸入流
PipedInputStream:管道流,執行緒間通訊,與PipedOutputStream配合使用
SequenceInputStream:合併流,將多個輸入流邏輯串聯。
OutputStream:此抽象類是表示輸出位元組流的所有類的超類
ByteArrayOutputStream:含緩衝陣列,將資料寫入記憶體中的位元組陣列,未涉及流
FileOutStream:檔案輸出流,將資料寫入檔案
BufferedOutputStream:帶有緩衝區的位元組輸出流
PrintStream:列印流,作為輸出列印
DataOutputStream:資料輸出流,寫入基本資料型別的資料
ObjectOutputStream:用於寫入物件的輸出流
PipedOutputStream:管道流,執行緒間通訊,與PipedInputStream配合使用
2、流操作規律:
明確源和目的:
資料來源:讀取,InputStream和Reader
目的:寫入:OutStream和Writer
資料是否是純文字:
是:字元流,Reader,Writer
否:位元組流,InputStream,OutStream
明確資料裝置:
源裝置:記憶體、硬碟、鍵盤
目的裝置:記憶體、硬碟、控制檯
是否提高效率:用BufferedXXX
3、轉換流:將位元組轉換為字元,可通過相應的編碼表獲得
轉換流都涉及到位元組流和編碼表
三、多執行緒
--à程序和執行緒:
1)程序是靜態的,其實就是指開啟的一個程式;而執行緒是動態的,是真正執行的單元,執行的過程。其實我們平時看到的程序,是執行緒在執行著,因為執行緒是作為程序的一個單元存在的。
2)同樣作為基本的執行單元,執行緒是劃分得比程序更小的執行單位。
3)每個程序都有一段專用的記憶體區域。與此相反,執行緒卻共享記憶體單元(包括程式碼和資料),通過共享的記憶體單元來實現資料交換、實時通訊與必要的同步操作。
1、建立執行緒的方式:
建立方式一:繼承Thread
1:定義一個類繼承Thread
2:覆蓋Thread中的run方法(將執行緒執行的程式碼放入run方法中)。
3:直接建立Thread的子類物件
4:呼叫start方法(內部呼叫了執行緒的任務(run方法));作用:啟動執行緒,呼叫run方法
方式二:實現Runnable
1:定義類實現Runnable介面
2:覆蓋Runnable介面中的run方法,將執行緒的任務程式碼封裝到run中
3:通過Thread類建立執行緒物件
4、並將Runnable介面的子類物件作為Thread類的建構函式引數進行傳遞
作為引數傳遞的原因是讓執行緒物件明確要執行的run方法所屬的物件。
區別:
繼承方式:執行緒程式碼放在Thread子類的run方法中
實現方式:執行緒存放在介面的子類run方法中;避免了單繼承的侷限性,建議使用。
2、執行緒狀態:
新建:start()
臨時狀態:具備cpu的執行資格,但是無執行權
執行狀態:具備CPU的執行權,可執行
凍結狀態:通過sleep或者wait使執行緒不具備執行資格,需要notify喚醒,並處於臨時狀態。
消亡狀態:run方法結束或者中斷了執行緒,使得執行緒死亡。
3、多執行緒安全問題:
多個執行緒共享同一資料,當某一執行緒執行多條語句時,其他執行緒也執行進來,導致資料在某一語句上被多次修改,執行到下一語句時,導致錯誤資料的產生。
因素:多個執行緒操作共享資料;多條語句操作同一資料
解決:
原理:某一時間只讓某一執行緒執行完操作共享資料的所有語句。
辦法:使用鎖機制:synchronized或lock物件
4、執行緒的同步:
當兩個或兩個以上的執行緒需要共享資源,他們需要某種方法來確定資源在某一刻僅被一個執行緒佔用,達到此目的的過程叫做同步(synchronization)。
同步程式碼塊:synchronized(物件){},將需要同步的程式碼放在大括號中,括號中的物件即為鎖。
同步函式:放於函式上,修飾符之後,返回型別之前。
5、wait和sleep的區別:(執行權和鎖區分)
wait:可指定等待的時間,不指定須由notify或notifyAll喚醒。
執行緒會釋放執行權,且釋放鎖。
sleep:必須制定睡眠的時間,時間到了自動處於臨時(阻塞)狀態。
即使睡眠了,仍持有鎖,不會釋放執行權。
Android下的程序與執行緒:
1、程序的生命週期:
1)、程序的建立及回收:
程序是被系統建立的,當記憶體不足的時候,又會被系統回收
2)、程序的級別:
Foreground Process 前臺程序
Visible Process 可視程序
Service Process 服務程序:可以提高級別的
Background Process 後臺程序
Empty Process 空程序(無元件啟動,做程序快取使用,恢復速度快)
☆ Android技能
« 熟練掌握Android四大元件,常用的佈局檔案,自定義控制元件等
Android中4大元件是:ContentProvider、Activity、BroadcastReceiver和Service
清單檔案:
1、所有的應用程式必須要有清單檔案
在manifest節點下需要聲明當前應用程式的包名
2、包名:宣告包的名字,必須唯一
如果兩個應用程式的包名和簽名都相同,後安裝的會覆蓋先安裝的
3、宣告的程式的元件(4大元件)
其中比較特殊的是廣播接收者,可以不在清單檔案中配置,可以通過程式碼進行註冊
4、宣告程式需要的許可權:保護使用者的隱私
5、可以控制服務在單獨的程序中的,四大元件都可以配置這個屬性process
在元件節點配置process:
如:android:process="xxx.ooo.xxx"
比如說:處理圖片的時候,會很耗記憶體,就需要在單獨的新的程序中,可以減少記憶體溢位的機率
一、ContentProvider內容提供者
1、特點
①、可以將應用中的資料對外進行共享;
②、資料訪問方式統一,不必針對不同資料型別採取不同的訪問策略;
③、內容提供者將資料封裝,只暴露出我們希望提供給其他程式的資料(這點有點類似Javabeans);
④、內容提供者中資料更改可被監聽;
2、建立內容提供者
Ø 定義類繼承ContentProvider,根據需要重寫其內容方法(6個方法):
l onCreate() 建立內容提供者時,會呼叫這個方法,完成一些初始化操作;
l crud相應的4個方法 用於對外提供CRUD操作;
l getType() 返回當前Url所代表資料的MIME型別:
返回的是單條記錄:以vnd.android.cursor.item/ 開頭,如:vnd.android.cursor.item/person
返回的是多條記錄:以vnd.android.cursor.dir/ 開頭,如:vnd.android.cursor.dir/person
Ø 在清單檔案的<application>節點下進行配置,<provider>標籤中需要指定name、authorities、exported屬性
l name: 為全類名;
l authorities: 是訪問Provider時的路徑,要唯一;
l exported: 用於指示該服務是否能夠被其他應用程式元件呼叫或跟它互動
Ø URI代表要操作的資料,由scheme、authorites、path三部分組成:
l content://com.itheima.sqlite.provider/person
l scheme: 固定為content,代表訪問內容提供者;
l authorites: <provider>節點中的authorites屬性;
l path: 程式定義的路徑,可根據業務邏輯定義;
Ø 操作 URI的UriMather與ContentUris工具類:
當程式呼叫CRUD方法時會傳入Uri
l UriMatcher:表示URI匹配器,可用於新增Uri匹配模式,與匹配Uri(見下程式碼);
l ContentUris:用於操作Uri路徑後面的ID部分,2個重要的方法:
1. withAppendedId(uri, id) 為路徑加上ID部分;
2. parseId(uri) 用於從路徑中獲取ID部分;
示例程式碼(內容提供者類):
public classHeimaProvider extends ContentProvider {
private static final int PERSON = 1; // 匹配碼
private static final int STUDENT = 2; // 匹配碼
private static final int PERSON_ID = 3; // 匹配碼
private MyHelper helper;
/** Uri匹配器 */
private UriMatcher uriMatcher = newUriMatcher(UriMatcher.NO_MATCH);
@Override
public boolean onCreate() {
System.out.println("onCreate...");
helper = newMyHelper(getContext());
// == 新增 uri 匹配模式, 設定匹配碼(引數3) Uri如果匹配就會返回相應的匹配碼 ==
uriMatcher.addURI("com.itheima.sqlite.provider","person", PERSON);
uriMatcher.addURI("com.itheima.sqlite.provider","#", PERSON_ID); // #表示匹配數字,*表示匹配文字
uriMatcher.addURI("com.itheima.sqlite.provider","student", STUDENT);
return true;
}
@Override
public Uri insert(Uri uri, ContentValuesvalues) {
SQLiteDatabase db =helper.getWritableDatabase();
switch (uriMatcher.match(uri)) { // 匹配uri
case PERSON:
long id =db.insert("person", "id", values);
db.close();
returnContentUris.withAppendedId(uri, id); //在原uri上拼上id,生成新的uri並返回;
case STUDENT:
long insert =db.insert("student", "id", values);
System.out.println("資料檔案中,沒有student表,也不會報錯");
db.close();
returnContentUris.withAppendedId(uri, insert); //為路徑上,加上ID
default:
throw newIllegalArgumentException(String.format("Uri:%s 不是合法的uri地址", uri));
}
}
@Override
public int delete(Uri uri, Stringselection, String[] selectionArgs) {
SQLiteDatabase db =helper.getWritableDatabase();
switch (uriMatcher.match(uri)) { // 匹配uri
case PERSON_ID:
long parseId =ContentUris.parseId(uri); // 獲取傳過來的ID值
selection = "id=?"; //設定查詢條件
selectionArgs = newString[] { parseId + "" }; //查詢條件值
case PERSON:
int delete =db.delete("person", selection, selectionArgs);
db.close();
return delete;
default:
throw newIllegalArgumentException(String.format("Uri:%s 不是合法的uri地址", uri));
}
}
@Override
public int update(Uri uri, ContentValuesvalues, String selection, String[] selectionArgs) {
SQLiteDatabase db =helper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case PERSON_ID:
long parseId =ContentUris.parseId(uri); //獲取傳過來的ID值
selection ="id=?"; //設定查詢條件
selectionArgs = newString[] { parseId + "" }; //查詢條件值
case PERSON:
int update =db.update("person", values, selection, selectionArgs);
db.close();
return update;
default:
throw newIllegalArgumentException(String.format("Uri:%s 不是合法的uri地址", uri));
}
}
@Override
public Cursor query(Uri uri, String[]projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase db =helper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case PERSON_ID:
// == 根據ID查詢 ==
long parseId =ContentUris.parseId(uri); //獲取傳過來的ID值
selection ="id=?"; //設定查詢條件
selectionArgs = newString[] { parseId + "" }; // 查詢條件值
case PERSON:
Cursor cursor =db.query("person", projection, selection, selectionArgs, null, null,sortOrder);
// == 注意:此處的 db與cursor不能關閉 ==
return cursor;
default:
throw newIllegalArgumentException(String.format("Uri:%s 不是合法的uri地址", uri));
}
}
// 返回傳入URI的型別,可用於測試URI是否正確
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case PERSON_ID:
return"vnd.android.cursor.item/person"; //表示單條person記錄
case PERSON:
return"vnd.android.cursor.dir/person"; //表單多個person記錄
default:
return null;
}
}
}
清單中的配置:
<provider
android:exported="true"
android:name="com.itheima.sqlite.provider.HeimaProvider"
android:authorities="com.itheima.sqlite.provider" />
authorities 可以配置成如下形式(系統聯絡人的):
android:authorities="contacts;com.android.contacts"
“;” 表示的是可使用 contacts, 與 com.android.contacts
3、內容解析者ContentResolver
通過Context獲得ContentResolver內容訪問者物件(內容提供者的解析器物件);
呼叫ContentResolver物件的方法即可訪問內容提供者
測試類程式碼:
public class HeimaProviderTest extends AndroidTestCase {
/** 測試新增資料*/
public void testInsert() {
ContentResolver resolver =this.getContext().getContentResolver();
Uri uri =Uri.parse("content://com.itheima.sqlite.provider/person");
ContentValues values = newContentValues();
values.put("name","小翼");
values.put("balance",13000);
Uri insert = resolver.insert(uri,values); // 獲取返回的uri,如:content://com.itheima.sqlite.provider/7
System.out.println(insert);
}
/** 測試刪除*/
public void testRemove() {
ContentResolver resolver = this.getContext().getContentResolver();
Uri uri =Uri.parse("content://com.itheima.sqlite.provider/person");
int count = resolver.delete(uri,"id=?", new String[] { 3 + "" });
System.out.println("刪除了" + count + "行");
}
/** 測試更新*/
public void testUpdate() {
ContentResolver resolver =this.getContext().getContentResolver();
Uri uri =Uri.parse("content://com.itheima.sqlite.provider/person");
ContentValues values = newContentValues();
values.put("name","小趙update");
values.put("balance",56789);
int update = resolver.update(uri,values, "id=?", new String[] { 6 + "" });
System.out.println("更新了" + update + "行");
}
/** 測試查詢*/
public void testQueryOne() {
ContentResolver resolver =this.getContext().getContentResolver();
Uri uri = Uri.parse("content://com.itheima.sqlite.provider/person");
Cursor c = resolver.query(uri, newString[] { "name", "balance" }, "id=?", newString[] { 101 + "" }, null);
if (c.moveToNext()) {
System.out.print(c.getString(0));
System.out.println("" + c.getInt(1));
}
c.close();
}
/**測試查詢全部*/
public void testQueryAll() {
ContentResolver resolver =this.getContext().getContentResolver();
Uri uri =Uri.parse("content://com.itheima.sqlite.provider/person");
Cursor c = resolver.query(uri, newString[] { "id", "name", "balance" }, null, null,"name desc");
while (c.moveToNext()) {
System.out.println(c.getInt(0)+ ", " + c.getString(1) + ", " + c.getInt(2));
}
c.close();
}
/** 測試查詢一條*/
public void testQueryOneWithUriId() {
ContentResolver resolver =this.getContext().getContentResolver();
Uri uri =Uri.parse("content://com.itheima.sqlite.provider/3"); // 查詢ID為3的記錄
Cursor c = resolver.query(uri, newString[] { "id", "name", "balance" }, null, null,null);
if (c.moveToNext()) {
System.out.println(c.getInt(0)+ ", " + c.getString(1) + ", " + c.getInt(2));
}
c.close();
}
/** 測試獲取內容提供者的返回型別*/
public void testGetType() {
ContentResolver resolver =this.getContext().getContentResolver();
System.out.println(resolver.getType(Uri.parse("content://com.itheima.sqlite.provider/2")));
System.out.println(resolver.getType(Uri.parse("content://com.itheima.sqlite.provider/person")));
}
}
4、監聽內容提供者的資料變化
在內容提供者中可以通知其他程式資料發生變化
通過Context的getContentResolver()方法獲取ContentResolver
呼叫其notifyChange()方法傳送資料修改通知,傳送到系統的公共記憶體(訊息信箱中)
在其他程式中可以通過ContentObserver監聽資料變化
通過Context的getContentResolver()方法獲取ContentResolver
呼叫其registerContentObserver()方法指定對某個Uri註冊ContentObserver
自定義ContentObserver,重寫onChange()方法獲取資料
示例程式碼(發通知部分):
public int delete(Uri uri, Stringselection, String[] selectionArgs) {
SQLiteDatabase db =helper.getWritableDatabase();
int delete =db.delete("person", selection, selectionArgs);
// == 通過內容訪問者物件ContentResolve 發通知給所有的Observer ==
getContext().getContentResolver().notifyChange(uri,null);
db.close();
returndelete;
}
}
監聽部分:
// 註冊內容觀察者事件
private voidinitRegisterContentObserver() {
Uri uri =Uri.parse("content://com.itheima.sqlite.provider"); // 監聽的URI
// == 第2個引數:true表示監聽的uri的後代都可以監聽到 ==
getContentResolver().registerContentObserver(uri,true, new ContentObserver(new Handler()) {
public voidonChange(boolean selfChange) { //接到通知就執行
personList =personDao.queryAll();
((BaseAdapter)personListView.getAdapter()).notifyDataSetChanged();
}
});
}
5、區別Provider/Resolver/Observer
1)ContentProvider:內容提供者
把一個應用程式的私有資料(如資料庫)資訊暴露給別的應用程式,讓別的應用程式可以訪問;
在資料庫中有對應的增刪改查的方法,如果要讓別的應用程式訪問,需要有一個路徑uri:
通過content:// 路徑對外暴露,uri寫法:content://主機名/表名
2)ContentResolver:內容解析者
根據內容提供者的路徑,對資料進行操作(crud);
3)ContentObserver:內容觀察者
可以理解成android系統包裝好的回撥,資料傳送變化時,會執行回撥中的方法;
ContentResolver傳送通知,ContentObserver監聽通知;
當A的資料發生變化的時候,A就會顯示的通知一個內容觀察者,不指定觀察者,就會發訊息給一個路徑
二、Activity活動
描述:
1)表示使用者互動的一個介面(活動),每一個activity對應一個介面
2)是所有View的容器:button,textview,imageview;我們在介面上看到的都是一個個的view
3)有個ActivityManager的管理服務類,用於維護與管理Activity的啟動與銷燬;
Activity啟動時,會把Activity的引用放入任務棧中
4)一個應用程式可以被別的應用程式的activity開啟
此時,是將此應用程式的引用加入到了開啟的那個activity的任務棧中了
5) activity是執行在自己的程式程序裡面的
在一個應用程式中,可以申請單獨的程序,然此應用程式中的一個元件在新的程序中執行
6)可以在activity裡面新增permission標籤,呼叫者必須加入這個許可權
與錢打交道的介面,都不允許被其他應用程式隨意開啟
如果覺得那個activity比較重要,可以在清單檔案中配置,防止別人隨意開啟,需要配置一個許可權
自定義許可權:
在清單檔案中配置permission,建立一個新的許可權
建立後,就會在清單檔案中生成這個許可權了
此時,需要開啟這個介面,就需要使用這個許可權
Tips:
*不可使用中文文字,需要使用字串,抽取出來
*宣告之後,會在gen的目錄下,多出來一個檔案:Manifest的檔案,系統也存在一個這樣的檔案
1、建立Activity
1)定義類繼承自Activity類;
2)在清單檔案中Application節點中宣告<activity>節點;
<activity
android:name="com.itheima.activity.MainActivity"
android:label="@string/app_name" >
<!-- 程式的入口,LAUNCHER表示桌面快捷方式,進入的是此Activity -->
<intent-filter>
<actionandroid:name="android.intent.action.MAIN" />
<categoryandroid:name="android.intent.category.LAUNCHER" /> <!—啟動時,預設匹配 --
</intent-filter>
</activity>
2、啟動Activity
通過意圖(Intent)來啟動一個Activity;
1) 顯示啟動:
顯示啟動一般用於自己呼叫自己的情況(在當前應用找),這樣的啟動方式比較快速,建立Intent後指定包名和類名;
Intent intent = new Intent(this,OtherActivity.class);
startActivity(intent); // 啟動新的Activity
或者:
Intent intent = new Intent();
intent.setClassName("com.itheima.activity","com.itheima.activity.OtherActivity"); // 包名、全類名
startActivity(intent); // 啟動新的Activity
2)隱式啟動:
一般用於呼叫別人的Activity,建立Intent後指定動作和資料以及型別;
// 電話
Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL); // 設定動作
intent.setData(Uri.parse("tel://123456")); // 設定資料
// 網頁
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://192.168.1.45:8080/androidWeb"));
// 音訊/視訊,設定type
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/daqin.mp3"),"audio/*"); // 設定資料和資料型別,將啟動音訊播放器(vedio)
3)為隱式啟動配置意圖過濾器:
n 顯式意圖是指在建立意圖時指定了元件,而隱式意圖則不指定元件,通過動作、型別、資料匹配對應的元件;
n 在清單檔案中定義<activity>時需要定義<intent-filter>才能被隱式意圖啟動;
n <intent-filter>中至少配置一個<action>和一個<category>,否則無法被啟動;
n Intent物件中設定的action、category、data在<intent-filter>必須全部包含Activity才能啟動;
n <intent-filter>中的<action>、<category>、<data>都可以配置多個,Intent物件中不用全部匹配,每樣匹配一個即可啟動;
n 如果一個意圖可以匹配多個Activity,Android系統會提示選擇;
<!--註冊 Activity, lable 表示Activity的標題 -->
<activity
android:name="com.itheima.activity.OtherActivity"
android:label="OtherActivity">
<!-- 配置隱式意圖,匹配http -->
<intent-filter>
<actionandroid:name="android.intent.action.VIEW" /> <!—必須,表示動作為View -->
<data android:scheme="http"/> <!—http開頭-->
<category android:name="android.intent.category.DEFAULT"/> <!-- 必須,表示啟動時,預設匹配-->
</intent-filter>
<!-- 匹配tel -->
<intent-filter>
<actionandroid:name="android.intent.action.CALL" />
<data android:scheme="tel"/>
<categoryandroid:name="android.intent.category.DEFAULT" /> <!-- 必須,表示啟動 -->
</intent-filter>
<!-- 匹配 音訊、視訊 -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<dataandroid:scheme="file" android:mimeType="audio/*" /> <!—檔案協議l型別 -->