編輯:關於Android編程
Intent 的 ComponentName 廣播-BroadcastReceiver ContentProvider AIDL
Intent作為我們最常用的數據傳輸渠道,特別是通過Intent打開一個Activity,想必每個人都不會陌生。通常我們用到的都是通過Intent打開同一個進程(App)內部的Activity,如果想實現跨進程通訊,就需要把Intent對象發送到另一個(App)中,並解析出來,這時就需要ComponentName來為我們做這件事情了。既然可以發送數據到另外的進程,也就可以實現不同進程間的交互了。
注意事項:如果A要打開另一個進程中的B中的Activity,那麼要在B項目中的AndroidManifest文件中,把要打開的Activity的exported設置為true ,否則將會報錯。
android:exported="true"
我們將要用到ComponentName的構造函數如下:
public ComponentName(String pkg, String cls) {
if (pkg == null) throw new NullPointerException("package name is null");
if (cls == null) throw new NullPointerException("class name is null");
mPackage = pkg;
mClass = cls;
}
它需要兩個參數,第一個參數是一個存在的pakage(包),第二個是這個包中你要打開的類的名字(注意是帶完整包名的),下面是使用例子:
進程AndroidAIDL(com.example.androidaidl)中的MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//接收傳過來的Intent
if (getIntent() != null){
System.out.println("----------"+getIntent().getIntExtra("id", 0)+"----------");
}
}
另一個進程AndroidTest,在這裡的MainActivity中我們寫如下代碼:
/**指定包名和帶包名的Activity的名字*/
ComponentName componentName = new ComponentName("com.example.androidaidl", "com.example.androidaidl.MainActivity");
Intent intent = new Intent();
intent.putExtra("id", 1001);
intent.setComponent(componentName);
startActivity(intent);
運行上面代碼後,會看到LogCat中打印出 1001,表示接收AndroidTest進程傳來的Intent正常。
注意事項:上面代碼中我們傳遞的是基本的數據類型,對於基本數據類型,比如Int,String等接收時可以像上面那樣直接讀取,但是如果發送的是復雜的對象,該對象需要實現Serializable或者Parcelable接口。
比如我們定義一個 SendData 對象作為傳遞對象,它實現 Parcelable 接口:
public class SendData implements Parcelable{
int id;
String content;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
@Override
public SendData createFromParcel(Parcel source) {
// TODO Auto-generated method stub
SendData data = new SendData();
data.setId(source.readInt());
data.setContent(source.readString());
return data;
}
@Override
public SendData[] newArray(int size) {
// TODO Auto-generated method stub
return new SendData[size];
}
};
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeInt(id);
dest.writeString(content);
}
}
發送代碼:
Intent intent = new Intent();
SendData data = new SendData();
data.setId(1001);
data.setContent("hellow world");
//發送序列化對象
intent.putExtra("data", data);
startActivity(intent);
接收代碼
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getIntent() != null){
if (getIntent().getParcelableExtra("data") == null)
return;
//讀取序列化對象,並轉化為SendData類型
SendData data = (SendData)getIntent().getParcelableExtra("data");
System.out.println("----------"+data.getContent()+"-----------");
}
}
如果在同一個進程的話,上面的方法沒有任何問題,如果在不同進程中,就要注意,SendData 這個bean所在的包名,在各個項目中必須一樣,否則接收方,無法解析
Android的廣播是系統級的,只要傳遞的Action一樣(下面的例子中,都使用 Action_Test),就可以接收到其他進程廣播的消息,廣播中可以通過Intent傳遞數據。
發送方代碼:
Intent intent = new Intent("Action_Test");
SendData data = new SendData();
data.setId(1001);
data.setContent("hellow world");
intent.putExtra("data", data);
intent.putExtra("id", 1001);
getActivity().sendBroadcast(intent);
接收方代碼(動態注冊廣播):
innerReceiver = new InnerReceiver();
IntentFilter filter = new IntentFilter("Action_Test");
registerReceiver(innerReceiver, filter);
class InnerReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (intent.getAction().equals("Action_Test")){
SendData data = (SendData)intent.getParcelableExtra("data");
System.out.println("-----------"+data.getContent()+"------------");
}
}
}
因為是通過Intent傳遞數據,所以對復雜對象的要求和第一種方式一樣,要求bean所在的包名一樣
ContentProvider通常用來操作數據集,Android本身就提供了不少的ContentProvider訪問,比如聯系人、相冊等。
訪問ContentProvider,需要通過Uri,需要以“content://”開頭。下面看看使用方法:
在進程AndroidAIDL(com.example.androidaidl),我們定義一個繼承自ContentProvider的類,需要重載它的方法,這裡我們以query為例
public class ProviderTest extends ContentProvider {
private static final UriMatcher MATCHER = new UriMatcher(
UriMatcher.NO_MATCH);
static{
//添加訪問字符串,對應配置文件中的android:authorities屬性
MATCHER.addURI("com.mh.getdata", "stock", 10001);
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
return false;
}
@Override
/**
* @param uri URI 路徑
* @param projection 要保護的列集合,如果傳 null,所有列都會被包含進去.
* @param selection 用來過濾數據集的規則,null表示不篩選.
* @param selectionArgs 類似字符串的格式化,selection參數中可以包含 ?s, 這個將被selectionArgs的內容替換
* @param sortOrder 排序.
*/
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
System.out.println("--------------------query----------------------");
return null;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
}
定義了這個類後,需要在AndroidManifest對它進行聲明,android:exported=true,記得要寫,否則會提示權限錯誤
上面的配置有兩個屬性
android:name就是類名成
android:authorities這個就是前面提到的Uri,外界需要通過這個來訪問Provider
下面看看調用者,在另一個進程中,我們有如下代碼:
ContentResolver resolver = getActivity().getContentResolver();
/**com.mh.getdata/stock這個要和Provider所在進程中添加的Uri一致*/
Uri uri = Uri.parse("content://com.mh.getdata/stock");
Cursor cursor = resolver.query(uri, null, null, null, null);
調用上面代碼後,LogCat中打印出 “query”字樣,表名Provider調用成功,我們通過resolver就可以和AndroidAIDL進程中的Provider對象進行交互了。
一種接口定義語言,Android會自動生成通訊代碼,通過AIDL我們可以在一個進程中,調用另一個進程中的方法,據說一些大公司的殺不死的Service就是通過這個AIDL來保活的,可以好好研究下。個人認為AIDL更適合做插件化系統,或者有多個app共同組成一個系統,比如WebView因為內存洩露比較嚴重,所以一些公司就單獨把WebView封裝成一個app,單獨調用,這時,我們通過AIDL技術,就可以調用到這個app中的接口,來操作WebView的行為。
下面開始介紹使用方法:
在兩個項目中新建普通文件(Eclipse中是:new ->General->File),記得同時寫上後綴名(aidl),兩個項目中這個文件所在的包名要保持一致,內容也要一樣,如圖
編譯之後, 會在gen目錄下,自動產生同名的,後綴為 java 的文件。裡面有我們要用到的 Stub類。
public static abstract class Stub extends android.os.Binder implements com.example.aidl.AidlFunctions
在接口文件AIDLFunctions.aidl中,我們定義一個方法 show
interface AidlFunctions{
void show();
}
服務端:
AIDL的使用,需要一個Service配合,所以我們在服務端還要聲明一個Service
public class AIDLService extends Service {
//stub就是系統自動產生的
AidlFunctions.Stub binder;
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
binder = new AidlFunctions.Stub() {
@Override
//這裡是我們在接口中聲明的方法的實現
public void show() throws RemoteException {
// TODO Auto-generated method stub
System.out.println("--------------------收到----------------------");
}
};
return binder;
}
}
在AndroidManifest聲明Service
客戶端:
//綁定服務,要用到ServiceConnection
private ServiceConnection serviceConnection;
//自定義的接口,和服務端一樣
private AidlFunctions aidlFunctions;
serviceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
System.out.println("--------------------ServiceDisconnected----------------------");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
System.out.println("--------------------ServiceConnected----------------------");
aidlFunctions = AidlFunctions.Stub.asInterface(service);
}
};
Intent intent = new Intent("com.example.androidaidl.AIDLService");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
//調用show方法
try {
aidlFunctions.show();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
前言:多年之前接觸過zxing實現二維碼,沒想到今日項目中再此使用竟然使用的還是zxing,百度之,竟是如此牛的玩意。當然,項目中我們也許只會用到二維碼的掃描和生成兩個功
前言最近遇到一個項目的應用要上微信登錄,大家都知道微信登錄是需要開放平台上申請的,在微信開發平台創建移動應用後,需要填寫:需要填寫的內容問題這裡的應用簽名是keystor
TextSwitcher的Java Doc是這樣描述自己的: Specialized ViewSwitcher that contains only children o
在開發過程中,與用戶交互式免不了會用到對話框以實現更好的用戶體驗,所以掌握幾種對話框的實現方法還是非常有必要的。在看具體實例之前先對AlertDialog做一個簡單介紹。