## 本文大綱
複製代碼
看完本文能收穫什麼?按目錄索引,你能夠學習到:html
組件間的通訊,Activity,fragment,Service, Provider,Receiverandroid
進程間的通訊,AIDLweb
線程間的通訊,Handler,AnsycTask,IntentService數據庫
多個App間的通訊編程
使用大型開源框架完成組件通訊,EventBus,otto數組
建議閱讀本文時遵循如下學習思路安全
研究對象:Activity,fragment等組件網絡
信息存在形式:Intent,Bundle,靜態變量,全局變量,仍是點擊事件,觸摸事件的回調監聽,或者文件形式(Sharepreference,SQLite,File , NetStream) ,本質就是信息源多線程
信息傳遞的形式:網路,回調監聽,線程,Intent,全局Application框架
相同形式的思路,不會出現第二次,請讀者觸類旁通
最後強調研究對象是單一的
1. 常規方式:Intent Bundle
經過Intent 啓動另外一個Activity時,有兩種重載方式:
startActivity(new Intent(),new Bundle());
startActivityForResult(new Intent(),FLAG,new Bundle());
複製代碼
從參數列表就能夠總結出來,有Intent,和Bundle,能夠傳遞8種基本數據類型和可序列化的數據類型,好比字符串和字節數組。提到可序列化,就引起 Intent和Bundle 的侷限性了:
不少人不理解爲何把Intent和Bundle放在一塊兒談,由於Intent 底層存儲信息的原理也是經過Bundle存儲!
2. 公有靜態變量
好比 public static String flag=「楊歐神」;
使用方式 好比在其餘Activity當中 FirstActivity.flag=「OCNYang」;
修改靜態變量的值
3. 基於物理形式:
好比 File,SQLite,Sharepreference
物理形式
4. 全局變量:
好比Application:Application是與Activity,Service齊名的組件,很是強大,它的特色是全局組件共用,單例形式存在,在其餘組件中,咱們只須要 Context.getApplication()
得到該對象的引用便可
首先都遵循,如何啓動它們,就如何傳遞信息的原則:
1. Activity與Fragment
1. 經過構造函數傳遞
2. 獲取Fragment的實例對象
//CustFragment 是自定義的fragment,參數列表也能夠本身定義咯,
getSupportFragmentManager().beginTransaction()
.add(new CustFragment(自定義的的參數列表),new String("參數"))
//------------------method two-----------------------
getSupportFragmentManager().findFragmentById(R.id.headlines_fragment);
//------------------method three----------------------
getSupportFragmentManager().findFragmentByTag("HeadLines");
複製代碼
聰明的讀者可能會問Fragment如何與Activity通訊相似的問題,這是個好問題,請注意咱們的研究的原則是單一目標原則,在這節我研究的是Activity,你的疑惑在後面都會一一解答
2. Activity與Service
Activity啓動Service的兩種方式:
//CustomService 是自定義Service,完成一些後臺操做
startService(new Intent(FirstActivity.this,CustomService.class));
bindService(new Intent(FirstActivity.this,CustomService.class)), new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//當前啓動的service 一些數據就會回調回這裏,咱們在Activity中操做這些數據便可
get
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
},flags);
複製代碼
從啓動方式就能夠看出,經過Bundle對象的形式存儲,經過Intent傳輸,來完成Activity向Service傳遞數據的操做
3. Activity與BroadcastReceiver
啓動廣播的形式也有兩種:
//method one !!!-----------------------------------------------
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
}
},new IntentFilter(),"",new Handler());
//method two !!!-----------------------------------------------
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
}
},new IntentFilter());
複製代碼
關於method one 的第三個參數Handler不少人會很費解
參照registerReceiver中源碼關於該Handler參數的解釋:
Handler identifying the thread that will receive the Intent. If null, the main thread of the process will be used.
定義了一個用於接收Intent的子線程,若是不填或者默認爲null,那麼就會在主線程中完成接收Intent的操做
很明顯,Activity與BroadcastReceiver通訊時,用的也是Intent傳遞,Bundle存儲。
4. 通信時的同步問題
這裏的同步通信問題,爲下文Fragment通信做鋪墊,不是這個問題不重要,不值得引發你注意,只是我想把問題放在它最應該出現的位置。
以上只是基礎的傳遞數據的形式,大部分都是靜態的,如今有一種需求,用戶操做Activity,發出了某些指令,好比按下,滑動,觸摸等操做,如何完成這些信息傳遞呢?這就要求同步了。
同步傳遞消息也很簡單,就是調用系統寫好的回調接口
首先咱們要知道,用戶 點擊,觸摸 這些行爲 也屬於 通訊的範疇—點擊和觸摸屬於 信息源; 好比用戶行爲進行點擊,那就實現 :
new Button(mCotext).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new ImageView(mCotext).invalidate();
}
});
複製代碼
經過此招提示指定的ImageView:嘿!老兄,你該刷新了
又或者 當用戶 進行觸摸操做,咱們須要實現放大縮小平移指定的區域:
new RelativeLayout(mCotext).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//縮放
v.setScaleX(1f);
v.setScaleY(1f);
//平移
v.setTranslationX(1f);
v.setTranslationY(1f);
v.setTranslationY(1f);
//旋轉
v.setRotation(2f);
v.setRotationX(2f);
v.setRotationY(2f);
v.invalidate();
return true;
}
});
複製代碼
嘿,你看,當用戶進行觸摸操做,咱們能夠經過回調onTouchListenter來完成「觸摸」這一操做
關於View重繪機制以及優化刷新UI的細節,不屬於本文討論範圍。
經過實例對象傳遞
一樣的,在 Fragment 中 getActivity()
能夠獲取到它相關聯的 Activity 實例,就能夠輕鬆獲取而且修改 Activity 的數據。
首先,兩個Fragment之間不可能直接通訊(非正規因素除外),Google官方提出的解決辦法是 經過相關聯的Activity來完成兩個Fragment的通訊
只須要記住三步:
1. 定義一個接口:
在讓Fragment關聯Activity以前,能夠在Fragment中定義一個接口,而後讓宿主Activity來實現這個接口。接着,在Fragment中捕獲這個接口,而且在onAttach()中 捕獲Activity實例
//只需關注接口是如何定義的,以及onAttack中的實現
public class HeadlinesFragment extends ListFragment {
//定義的接口引用
OnHeadlineSelectedListener mCallback;
// 自定義回調接口,宿主Activity必需要實現它
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// 在這裏只是爲了確保Activity實現了咱們定義的接口,若是沒有實現,則拋出異常
try {
mCallback = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
...
}
複製代碼
一旦 Activity 經過 OnHeadlineSelectedListener
的實例 mCallBack 回調 onArticleSelected()
,Fragment 就能夠傳遞信息給 Activity 了
例如 下面是 ListFragment 的一個回調方法,當用戶點擊了 list 中的 item,這個 Fragment 就會經過回調接口向宿主 Activity 傳遞事件
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// 向Activity傳遞事件信息
mCallback.onArticleSelected(position);
}
複製代碼
2. 在宿主Activity實現這個接口
怎麼實現?很簡單,參考下面代碼:
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// 用戶從從 HeadlinesFragment選中了一個標題
//響應用戶的操做,作一些業務邏輯
}
}
複製代碼
3. 向其餘Fragment傳遞信息 (完成通訊)
宿主Activity能夠經過findFragmentById()向指定的Fragment傳遞信息,宿主Activity能夠直接獲取Fragment實例,回調Fragment的公有方法
例如:
宿主Activity 包含了一個Listfragment用來展現條目信息,當每一個條目被點擊的時候,咱們但願ListFragment向另一個DetailsFragment傳遞一個信息用來 展現不一樣的細節
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// 用戶在 HeadlinesFragment中選中了一個item
//在activity中添加新的fragment
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article 對象 能夠複用, 咱們就不須要建立兩遍了
// 回調articleFrag 更新
articleFrag.updateArticleView(position);
} else {
// 建立 Fragment 併爲其添加一個參數,用來指定應顯示的文章
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// 將 fragment_container View 時中的內容替換爲此 Fragment ,
// 而後將該事務添加到返回堆棧,以便用戶能夠向後回滾
transaction.replace(R.id.fragment_container, newFragment);
int setTransition=TRANSIT_FRAGMENT_OPEN;
transaction.setTransition(setTransition);
transaction.addToBackStack(null);
// 執行事務
transaction.commit();
}
}
}
複製代碼
下面我寫了一個實例來供你們理解:
各個類的聯繫圖:
效果以下:
主要是如何得到Service實例的問題
總結來講兩步:
public class LocalService extends Service {
// 傳遞給客戶端的Binder
private final IBinder mBinder = new LocalBinder();
//構造Random對象
private final Random mGenerator = new Random();
/**
* 這個類提供給客戶端 ,由於Service老是運行在同一個進程中的
*/
public class LocalBinder extends Binder {
LocalService getService() {
// 當客戶端回調的時候,返回LoacalService實例
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/**交給客戶端回調的方法 */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// 綁定 LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// 解綁 service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/**button已經經過 android:onClick (attribute) 設置此方法響應用戶click*/
public void onButtonClick(View v) {
if (mBound) {
// 回調 LocalService的方法.
//由於在主線程中刷新UI,可能會形成線程阻塞,這裏只是爲了測試
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/**定義經過bindService 回調的Binder */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
//先經過Binder得到Service的內部類 LoacalBinder
LocalBinder binder = (LocalBinder) service;
// 如今能夠得到service對象了
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
複製代碼
除了這種回調的方式外
還有一種方式 是在Service中 發送廣播,
好比 在 Service 中 開啓了一個子線程執行任務,就在子線程的 run() 方法中去 sendBroadcast(intent);
數據用Intent封裝,傳遞形式用廣播
關於進程和線程的細節改天詳細說明,咱們首先了解一下進程和線程的概念:
當某個應用組件啓動且該應用沒有運行其餘任何組件時,Android 系統會使用單個執行線程爲應用啓動新的 Linux 進程。默認狀況下,同一應用的全部組件在相同的進程和線程(稱爲「主」線程)中運行。
若是某個應用組件啓動且該應用已存在進程(由於存在該應用的其餘組件),則該組件會在此進程內啓動並使用相同的執行線程。
可是,咱們也能夠安排應用中的其餘組件在單獨的進程中運行,併爲任何進程建立額外的線程。
各種組件元素的清單文件條目—:activity,servicer,eceiver 和 provider 均支持 android:process 屬性,此屬性能夠指定該組件應在哪一個進程運行。咱們能夠設置此屬性,使每一個組件均在各自的進程中運行,或者使一些組件共享一個進程,而其餘組件則不共享。 此外,咱們還能夠設置 android:process,使不一樣應用的組件在相同的進程中運行
以及瞭解一下 進程間通訊的概念
Android 利用遠程過程調用 (RPC) 提供了一種進程間通訊 (IPC) 機制,經過這種機制,由 Activity 或其餘應用組件調用的方法將(在其餘進程中)遠程執行,而全部結果將返回給調用方。這就要求把方法調用及其數據分解至操做系統能夠識別的程度,並將其從本地進程和地址空間傳輸至遠程進程和地址空間,而後在遠程進程中從新組裝並執行該調用。
而後,返回值將沿相反方向傳輸回來。 Android 提供了執行這些 IPC 事務所需的所有代碼,所以咱們只需集中精力定義和實現 RPC 編程接口便可。
要執行 IPC,必須使用 bindService() 將應用綁定到服務上。
具體實現 能夠 參考這個實例 和文末給出的官方文檔
Handler 和AsyncTask都是用來完成子線程和主線程即UI線程通訊的
均可以解決主線程 處理耗時操做,形成界面卡頓或者程序無響應ANR異常 這一類問題
Handler 是 一種機制【Handler+Message+Looper】,全部的數據經過Message攜帶,,全部的執行順序按照隊列的形式執行,Looper用來輪詢判斷消息隊列,Handler用來接收和發送Message
AsyncTask 是一個單獨的類,設計之初的目的只是爲了 異步方式完成耗時操做的,順即可以通知主線程刷新Ui,AsyncTask的內部機制則是維護了一個線程池,提高性能。
在這裏提供另外一種優雅的作法完成線程間的通訊:
擴展 IntentService 類
因爲大多數啓動服務都沒必要同時處理多個請求(實際上,這種多線程狀況可能很危險),所以使用 IntentService 類實現服務值得一試。
但如需同時處理多個啓動請求,則更適合使用該基類Service。
IntentService 執行如下操做:
如下是 IntentService 的實現示例:
public class HelloIntentService extends IntentService {
/**
* 必須有構造函數 必須調用父 IntentService(String)帶有name的構造函數來執行工做線程
*/
public HelloIntentService() {
super("HelloIntentService");
}
/**
* IntentService 調用默認的工做線程啓動服務
* 當此方法結束,, IntentService 服務結束
*/
@Override
protected void onHandleIntent(Intent intent) {
// 一般在這裏會執行一些操做,好比下載文件
//在這裏只是sleep 5 s
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
}
複製代碼
看吧,咱們只須要一個構造函數和一個 onHandleIntent() 實現便可。
對於Service 固然也有基礎一點的作法,來完成多線程的操做,只不過代碼量更多了:
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler 接收來自主線程的Message
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//執行任務,好比下載什麼的,這裏只是 讓線程sleep
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
// 手動中止服務,來處理下一個線程
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
//啓動線程. 注意咱們在主線程中建立了一些子線程, 這些線程都沒有加鎖同步. 這些現場都是後臺線程,因此不會阻塞UI線程
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Handler開始輪詢遍歷了
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// 每一次請求,都會經過handler發送Message
// startID只是爲了讓咱們知道正在進行的是哪個線程,以便於咱們中止服務
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// 不提供 binding, 因此返回空
return null;
}
@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
複製代碼
首先咱們要知道如下兩點:
Android最重要的功能之一,是能夠操做其餘應用,好比在咱們的應用中,須要使用地圖顯示公司地址,咱們無序在地圖應用程序中構建Activity,而是直接建立Intent查看 地址的請求,Android系統以後啓動 能夠在地圖上顯示 地址的應用。
1) 構建隱式的意圖
隱式意圖不用聲明要啓動的組件類名稱,而是聲明操做,好比查看,編輯,發送,或者獲取某項。
若是您咱們的數據是Uri,能夠這樣構建Intent:
//當咱們的應用經過startActivity()調用此Intent時,電話應用會發起向指定電話號碼呼叫
Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
複製代碼
這裏還有一些其餘Intent的操做和Uri數據對:
· 查看地圖:
// 基於地址的地圖位置
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// 基於經緯度的地圖位置
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
複製代碼
· 查看網頁:
Uri webpage = Uri.parse("http://www.ocnyang.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
複製代碼
有的同窗會問了,我從哪裏能夠知道,Intent能夠傳遞的 Uri的類型,或者其餘數據類型呢?
答:能夠查閱 Google Intent 的 API
2) 確認是否存在 接收意向的應用
注意:若是調用了意向,但設備上沒有可用於處理意向的應用,咱們的應用將崩潰。
要確認是否存在可響應意向的可用Activity,請調用 queryIntentActivities() 來獲取可以處理ntent 的Activity列表。 若是返回的 List 不爲空,則能夠安全地使用該意向。例如:
PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
boolean isIntentSafe = activities.size() > 0;
複製代碼
若是 isIntentSafe 是 true,則至少有一個應用將響應該意向。 若是它是 false,則沒有任何應用處理該意向。
3) 啓動指定Activity
當我指定意圖後,經過startActivity(intent);就能夠啓動指定Activity
此處有一個Google官方的示例:
// 構建Intent
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
// 肯定意圖能夠被接收
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;
//啓動指定應用
if (isIntentSafe) {
startActivity(mapIntent);
}
複製代碼
4) 顯示應用選擇器
好比咱們要完成 分享操做,用戶可使用多個App完成分享,咱們應明確顯示選擇器對話框,如圖
要顯示選擇器,須要使用Intent的createChooser()方法 建立Intent,並將其傳遞至 startActivity()
Intent intent = new Intent(Intent.ACTION_SEND);
...
String title = getResources().getString(R.string.chooser_title);
// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, title);
// Verify the intent will resolve to at least one activity
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(chooser);
}
複製代碼
這將顯示一個對話框,其中有響應傳遞給 createChooser() 方法的意向的應用列表,而且將提供的文本用做 對話框標題
經過Intent.startActivityForResult()來完成。
首先在啓動另外一個Activity時,咱們須要指定request code以便返回結果時,咱們能夠正常處理它。
static final int PICK_CONTACT_REQUEST = 1; // The request code
...
private void pickContact() {
Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
pickContactIntent.setType(Phone.CONTENT_TYPE);
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}
複製代碼
當用戶完成操做後,返回數據,系統會調用Activity的 onActivityResult()方法,
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 檢查requestCode是否真確
if (requestCode == PICK_CONTACT_REQUEST) {
// 確保請求時成功的
if (resultCode == RESULT_OK) {
// 完成咱們的業務邏輯
}
}
}
複製代碼
爲了成功處理結果,咱們必須瞭解Intent的格式,好比聯繫人返回的是帶內容的URI,照相機返回的是Bitmap
如何根據返回的URI來讀取數據,咱們須要對ContentResolver 和 ContentProvider 有了解
下面就是一個三者結合的獲取聯繫人的實例:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 檢查requestCode
if (requestCode == PICK_CONTACT_REQUEST) {
// 確保請求成功
if (resultCode == RESULT_OK) {
//得到選擇的聯繫人的URI
Uri contactUri = data.getData();
// 咱們只須要NUMBER這一列的信息,
String[] projection = {Phone.NUMBER};
// 顯示根據NUMBER查詢的結果
// We don't need a selection or sort order (there's only one result for the given URI)
// 在這裏咱們並無對查詢的結果進行排序,由於在主線程中進行這種數據庫操做,有可能阻塞線程
//優化方案是異步完成排序的操做,這裏只是展現多個App間的通訊
Cursor cursor = getContentResolver()
.query(contactUri, projection, null, null, null);
cursor.moveToFirst();
//從NUMBER那一列當中取回phone NUMBER
int column = cursor.getColumnIndex(Phone.NUMBER);
String number = cursor.getString(column);
//接下來就是要操做這些phone number了
}
}
}
複製代碼
要容許其餘應用開始您的Activity,須要 在相應元素的宣示說明文件中添加一個 元素。
例如,此處有一個在數據類型爲文本或圖像時處理 ACTION_SEND 意向的意向過濾器:
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
<data android:mimeType="image/*"/>
</intent-filter>
</activity>
複製代碼
定義操做,一般是系統定義的值之一,好比ACTION_SEND 或 ACTION_VIEW。
定義與Intent關聯的數據,只需經過 android:mimeType 指定咱們接收的數據類型,好比text/plain 或 image/jpeg。
全部的隱式Intent,都使用 CATEGORY_DEFAULT 進行定義
當Activity開始時,調用getIntent檢索開始Activity的Intent,
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = getIntent();
Uri data = intent.getData();
// 指出接收的數據類型
if (intent.getType().indexOf("image/") != -1) {
// 處理帶有圖片的Intent
} else if (intent.getType().equals("text/plain")) {
// 處理帶有文本的Intent
}
}
複製代碼
只需調用setResult指定結果代碼和Intent
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();
複製代碼
記住必須爲結果指定結果碼,一般爲 RESULT_OK 或 RESULT_CANCELED。
咱們也能夠在Intent中 用Bundle存儲額外的信息
細心的同窗可能發現一個問題:
啓動 Activity 有 startActivity() 和 startActivityForResult() 兩種啓動方式,返回結果的形式id偶有 setResult() 嗎?
若是開啓當前Activity的Intent可能須要結果,只需調用 setResult()。 若是原始 Activity 已調用 startActivityForResult(),則系統將向其傳遞您提供給 setResult() 的結果;不然,會忽略結果。
Github上很是火的兩大通訊組件EventBus和otto:
EventBus 是一個 Android 事件發佈/訂閱框架,經過解耦發佈者和訂閱者簡化 Android 事件傳遞,這裏的事件能夠理解爲消息,本文中統一稱爲事件。事件傳遞既可用於 Android 四大組件間通信,也能夠用戶異步線程和主線程間通信等等。
傳統的事件傳遞方式包括:Handler、BroadCastReceiver、Interface 回調,相比之下 EventBus 的優勢是代碼簡潔,使用簡單,並將事件發佈和訂閱充分解耦。
1)概念:
事件(Event):又可稱爲消息,本文中統一用事件表示。其實就是一個對象,能夠是網絡請求返回的字符串,也能夠是某個開關狀態等等。事件類型(EventType)指事件所屬的 Class。
事件分爲通常事件和 Sticky 事件,相對於通常事件,Sticky 事件不一樣之處在於,當事件發佈後,再有訂閱者開始訂閱該類型事件,依然能收到該類型事件最近一個 Sticky 事件。
訂閱者(Subscriber):訂閱某種事件類型的對象。當有發佈者發佈這類事件後,EventBus 會執行訂閱者的 onEvent 函數,這個函數叫事件響應函數。訂閱者經過 register 接口訂閱某個事件類型,unregister 接口退訂。訂閱者存在優先級,優先級高的訂閱者能夠取消事件繼續向優先級低的訂閱者分發,默認全部訂閱者優先級都爲 0。
發佈者(Publisher):發佈某事件的對象,經過 post 接口發佈事件。
本項目較爲簡單,整體設計和流程圖:
使用方式:
build.gradle 中加入依賴
compile 'org.greenrobot:eventbus:3.0.0'
複製代碼
代碼中指需三步
1. 定義事件:只須要是一個Java類
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
複製代碼
2. 完成訂閱者
//MessageEvent被Eventbus post提交的時候 將會回調這個方法
//這種方式 提示咱們能夠直接定義本身的事件
@Subscribe
public void onMessageEvent(MessageEvent event){
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
// 當一些其餘事件post提交的時候,回調這個方法
@Subscribe
public void handleSomethingElse(SomeOtherEvent event){
doSomethingWith(event);
複製代碼
在Activity或者Fragment中綁定訂閱者
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
複製代碼
3. 發佈事件:
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
複製代碼
好了,這篇文章就到這了。做爲新的一年,今天和你們瞎聊幾句,剛過完年,你們是否是和我同樣呢?
開玩笑的!說說本身吧,其實如今的過年給做者的感受是年味愈來愈淡了,今年回家做者在家一直是大門不出二門不邁,也沒有趕幾家親戚。卻是在家自由自在的當了幾天大少爺,天天睡到飯作好醒,固然也少不了遭父母嫌棄(嘻嘻~),更少不了被家裏催着相親,還好家人態度不是特別強硬,被我都拒見了(唉,程序猿共同的痛啊!在新的一年裏,恰好也是個人本命年,找個女友必定是今年的首要任務啊,嘿嘿~)。
再和你們聊聊工做方面,唉,往往聽到身邊的朋友和大家談論拿了多少年終獎 / 抽獎中MacBook / 搶了多少老闆紅包 / 老闆發了多少開門紅包,我都是無比羨慕啊,本身自來到這家公司什麼節日福利啊、年終獎啊、旅遊獎勵啊都與我再無瓜葛了有沒有啊!提及來都是淚啊~~~
當初,選擇這家初創公司,是十分看好這家公司的業務方向,也有很大的市場可以開發,想着跟着拼一波試試。雖然技術團隊人員不是太多,Android開發方面也是我獨立負責,但還算能保證業務的運做。但初創公司老是有不少你想不到的各類各樣的問題,最大的問題我本身感受是領導層根本不懂得留住有能力的人才,在這公司工做半年,身邊各部門的同事換了近兩輪,就技術部好點也流失近一半。領導卻不在乎,老是告訴你,人走了再去招新的就好了,沒一點初創公司應有的氣氛和人情味。就Android平臺來言,公司只是把開發的App做爲一個銷售渠道,根本不會做爲一個產品來作和維護。像大多走不遠的初創公司同樣,開發一個 v1.0 就沒有而後了。就轉戰下一個項目了。
幹到如今本身也算失望盡了,目前看看新請來的CTO的見識如何了,實在不行只能另尋他途了。
原本不應寫在這的,做爲新的一年推的第一篇文章,你們原諒個人囉嗦吧。