Android常見問題總結(二)
上一篇博客傳送門:Android常見問題總結(一)
6. 廣播的兩種注冊方法,有什么區別
Android四大組件之一的broadcast(廣播)擁有兩種不同的注冊方法:靜態注冊與動態注冊
靜態注冊
廣播靜態注冊指把廣播相應的信息寫在AndroidManifest.xml中,例子如下:
<receiver android:name=".StaticReceiver">
<intent-filter>
<action android:name="XXX" />
</intent-filter>
</receiver>
靜態廣播的好處在于:不需程序啟動即可接收,可用作自動啟動程序
動態注冊
廣播動態注冊指在程序中調用registerReceiver方法來注冊廣播,例子如下:
IntentFilter filter = new IntentFilter();
filter.addAction("XXX");
DynamicReceiver receiver = new DynamicReceiver();
registerReceiver(receiver, filter);
// 不使用后記得取消注冊
unregisterReceiver(receiver);
動態廣播的好處在于:程序適應系統變化做操作,但在程序運行狀態才能接收到
7. Intent的使用方法,可以傳遞哪些數據類型
Intent即意圖,是Android中連接四大組件的樞紐,Android中的Activity、Service和BroadcastReceiver都依靠Intent來啟動。
Intent對象的屬性大致包含七種,分別是Component、Action、Category、Data、Type、Extra、Flag。
Component
Component用于明確指定需要啟動的目標組件,使用方法如下:
Intent intent = new Intent();
// 方法一:傳入上下文參數與class參數
intent.setComponent(new ComponentName(context, XXX.class));
// 方法二:傳入包名與類名
intent.setComponent(new ComponentName(pkg, cls));
指定Component屬性的Intent已經明確了它將要啟動的組件,因此這種Intent也被稱為顯示Intent,沒有指定Component屬性的Intent被稱為隱試Intent。
Action、Category
Action代表Intent所要完成的一個抽象“動作”,而Category則用于為Action增加額外的附加類別信息,它們的使用方法如下:
Intent intent = new Intent();
// 設置一個字符串代表Action
intent.setAction(action);
// 添加一個字符串代表category
intent.addCategory(category1);
intent.addCategory(category2);
值得注意的是Action屬性是唯一的,但Category屬性可以有多個。通常設置了Action和Category來啟動組件的Intent就不指定Component屬性了,因此這種Intent被稱為隱試Intent。
Data、Type
Data屬性接受一個Uri對象,Data屬性通常用于向Action屬性提供操作的數據。Type屬性用于指定該Data屬性所指定Uri對應的MIME類型。它們的使用方法如下:
Intent intent = new Intent();
// 設置Data屬性
intent.setData(new Uri());
// 設置Type屬性
intent.setType(type);
// 同時設置Data和Type屬性
intent.setDataAndType(data, type);
值得注意的是Data屬性和Type屬性會互相覆蓋,如果需要同時設置Data屬性和Type屬性需要使用setDataAndType。
Extra
Intent的Extra屬性用于進行數據交換,Intent的Extra屬性值應該是一個Bundle對象(一個類似Map的對象,可以存入多個鍵值對,但存入的對象必須是基本類型或可序列化的),用法如下:
Intent intent = new Intent();
// 直接往Intent添加基本類型,在方法內也是把數據存入Bundle
// 該方法有多種重載
intent.putExtra(name, value);
// 新建Bundle
Bundle bundle = new Bundle();
// 往Bundle添加數據,XXX為基本類型
bundle.putXXX(key, value);
bundle.putXXXArray(key, value);
// 把Bundle添加進Intent
intent.putExtras(bundle);
Flag
Intent的Flag屬性用于為該Intent添加一些額外的控制旗標,Intent可調用addFlags方法來添加控制旗標。
8. ContentProvider使用方法
為了在應用程序之間交換數據,Android提供了ContentProvider。當一個應用程序需要把自己的數據暴露給其他程序使用時,該應用程序就可以通過ContentProvider來實現,而其他程序則使用ContentResolver來操作ContentProvider暴露的數據。
實現ContentProvider的Java代碼如下:
public class MyProvider extends ContentProvider {
@Override
public boolean onCreate() {
// 第一次創建時調用,如果創建成功則返回true
// 可以在這里打開數據庫什么的
return true;
}
@Override
public String getType(Uri uri) {
// 返回ContentProvider所提供數據的MIME類型
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// 實現查詢方法
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// 實現插入方法,返回插入條數
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 實現刪除方法,返回刪除條數
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// 實現更新方法,返回更新條數
return 0;
}
}
當我們實現了自己的ContentProvider后,還需要去AndroidManifest.xml中注冊才行:
<provider
android:name=".MyProvider"
android:authorities="com.example.test.provider"
android:exported="true" />
配置ContentProvider時我們需要設置如下屬性:
- name:類名
- authorities:為ContentProvider指定一個對應的Uri,其他程序通過這個Uri來找到該ContentProvider
- exported:允許ContentProvider被其他應用調用
當其他應用需要訪問我們提供的ContentProvider的使用,只需使用ContentResolver并傳入相應的Uri即可:
public class MyActivity extends Activity {
private static String TAG = "MyActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ContentResolver resolver = getContentResolver();
// 傳入對應的Uri進行增刪查改操作
resolver.query(uri, projection, selection, selectionArgs, sortOrder);
resolver.insert(url, values);
resolver.delete(url, where, selectionArgs);
resolver.update(uri, values, where, selectionArgs);
}
}
除此之外,我們還可以使用ContentObserver來為ContentProvider添加觀察者。我們在其他程序的ContentResolver中注冊ContentObserver,當ContentProvider發生改變時,我們在數據改動的使用調用:
getContext().getContentResolver().notifyChange(uri, null);
那么此時ContentObserver中的onChange回調方法就會被調用,我們就可以簡單地監聽ContentProvider的數據改變了。
9. Thread、AsycTask、IntentService的使用場景與特點
Thread、AsyncTask和IntentService都與多線程有關,當我們在Android中涉及并發編程時(進行網絡請求、加載較大的文件等操作)就需要使用。
Thread
Java中的子線程,可以通過傳入Runnable接口或繼承Thread重寫run方法新建。
AsyncTask
由Java線程池改造的異步任務工具,在我的博文: Android 多線程編程中有提及。
IntentService
Android四大組件之一的Service默認是在主線程中運行的,IntentService是Service的子類,有如下特點:
- IntentService會創建單獨的worker線程來處理所有的Intent請求
- 當所有請求處理完成后,IntentService會自動停止
- 為Service的onBind方法提供了默認實現,返回null
- 為Service的onStartCommand方法提供了默認實現,把請求Intent添加到隊列中
實現IntentService的例子如下:
public class MyIntentService extends IntentService {
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
// IntentService會創建單獨的worker線程來處理此處的代碼
}
}
我們只需重寫onHandleIntent方法即可,該方法的代碼會在一個子線程中運行。
10. 五種布局: FrameLayout 、 LinearLayout 、 AbsoluteLayout 、 RelativeLayout 、TableLayout 各自特點
FrameLayout
FrameLayout即單幀布局,在該布局中的所有空間都會被置于布局的左上角。
LinearLayout
LinearLayout即線性布局,使用該布局必須為其指定orientation屬性(排列方向屬性,可以設置為水平或垂直的),其中的空間就會根據設置的屬性呈水平或垂直排列。
AbsoluteLayout
AbsoluteLayout即絕對布局,對布局中的控件我們使用x,y坐標值進行定位。
RelativeLayout
RelativeLayout即相對布局,在其中的控件可以相對于父布局或布局中別的控件的位置進行定位布局。
TableLayout
TableLayout即表格布局,TableLayout中的每一行的控件由TableRow包含,最終的布局效果會呈現成表格狀。
RelativeLayout