論Android中的值傳遞,論Android值傳遞
首先慶祝一下本人部落格滿一年,求撒花!
眾所周知,根據mvc設計模式,資料是要通過model來傳遞的,從一個activity(以下簡稱A)到另外一個activity(以下簡稱B)如果要傳值的話我們可以將model放到intent中(也可以不放),然後在B建立之後取得相應的值;反之,如果從B回傳值給A的話,也是可行的,只不過要在A的onActivityResult中接收相應的值。這幾種方法各有優缺點,大家自己可以結合實際情況來選擇。
本文的中心思想交代完畢,下面就開始看具體的代碼示範吧。
一、通過model傳值
public class DataSource { public Job job; private static DataSource instanceDataSource; public static DataSource shareInstance(){ if (null == instanceDataSource) { instanceDataSource = new DataSource(); } return instanceDataSource; }}
好,假設我們現在有一個工作列表頁(JobActivity,圖一)和工作詳情頁(JobDetailActivity,圖二),最常見的情形莫過於挑選清單頁的某個item,進入詳情頁。那麼傳值的話核心代碼如下:
//位於JobActivity中,點擊列表頁的某項,相應了listview的onItemClick方法public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Intent intent = new Intent(); //mJobs這個成員變數是Listview的資料來源,給資料來源的某個model(即job)賦值,由於datasource 是單例,所有的成員變數一旦賦值,就會常駐記憶體,不會變化,因此傳遞的值是不會變化的 DataSource.shareInstance().job = JobActivity.this.mJobs.get(position); intent.setClass(this, JobDetailActivity.class); this.startActivity(intent); }
以下是接受值的核心代碼
//位於JobDetailActivity中,在oncreate方法中protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_job_detail); //取得相應的model Job job = DataSource.shareInstance().job; //雖然多此一舉,但還是做個判斷吧,哈哈! if (null != job) { titleTextView = (TextView) findViewById(R.id.jobdetail_title_textview); titleTextView.setText(null != job.jobName ? job.jobName : ""); areaTextView = (TextView) findViewById(R.id.jobdetail_area_textview); areaTextView.setText(null != job.workArea ? job.workArea : ""); salaryTextViearw = (TextView) findViewById(R.id.jobdetail_salary_textview); salaryTextViearw.setText(null != job.workSalary ? job.workSalary : ""); companyTextView = (TextView) findViewById(R.id.jobdetail_company_textview); companyTextView.setText(null != job.workCompany ? job.workCompany : ""); contactTextView = (TextView) findViewById(R.id.jobdetail_contact_textview); contactTextView.setText(null != job.workContact ? job.workContact : ""); }}
這種傳值方式最大的優勢就是通俗易懂,簡單粗暴。而且確實是使用了mvc設計模式的,最主要的是可以實現雙向傳值,也就是從A到B可以傳遞,從B到A也可以,相當方便,是進階優秀程式員的必備方法,缺點也是有的:
(1),對象常駐記憶體,如果遇到大的model的話會比較吃記憶體(當然,也可以通過及時設定model為null來解決這個問題。)
(2)因為DataSource是單例,多線程肯定是要考慮的問題了。本文為了示範方便,沒有考慮並發的情況。但開發中就必須要考慮了,試想一種情況,主線程在擷取job對象後,後台我們啟動的某個線程在更改job對象的值,然後呢。。。。。資料肯定是會出問題了!總而言之,這是考驗閣下技術的最好的傳值方法。
Android 的設計人員命名總是讓人有些摸不透,比如頁面不像ios一樣叫controller,也不叫page,而是叫Activity。兩個Activity傳值的類取名intent,也就是“意圖”的意思,實在不知道他們的“意圖”是什麼。
廢話少說,直接上核心代碼:
intent傳遞model的核心方法是:
Intent putExtra(String name, Bundle value)
這個bundle就是我們將要傳遞的對象了
首先,我們要序列化我們的Job對象:
//job類後面的 implements Serializable兩個關鍵字就是序列化!public class Job implements Serializable{ public String jobName; public String jobId; public String workArea; public String workTime; public String workSalary; public String workDescription; public String workCompany; public String workContact; public String poster;}
下面開始傳值啦!
Intent intent = new Intent(this,JobDetailActivity.class); Bundle bundle = new Bundle(); //job對象是之前序列化了的對象 bundle.putParcelable(PAR_KEY, job); intent.putExtras(bundle);
第二種方法示範完畢,不知大家看了以後有沒有什麼感受,是不是感覺沒有第一種爽?但還可以啦,湊合湊合看看吧,繼續往下就更麻煩了,繼續遵循我們的由易到難原則往下看吧!
二、通過intent回傳值
1.回傳值不管在ios或者Android上都是相對來說比較麻煩的,ios中初期通過代理傳遞,後期如果技術可以了,您可以直接把傳值跟傳遞控制權分開來玩耍,很帶感!
Android中回傳值涉及到兩個方法
startActivityForResult() onActivityResult()
設想一個情境,JobActivity中要實現根據地區篩選工作,那麼你就得有一個地區選擇頁面(AreaSelectActivity,見圖三),選擇地區回來後重新重新整理Listview來載入相應地區的工作。
所以,我們要在使用者在AreaSelectActivity上選擇地區後把AreaSelectActivity這個頁面finish掉,然後告訴JobActivity使用者選擇了某個地區,需要把所有這個地區的工作過濾出來。
好了,背景交代完畢,接下來開始動手吧。
1.在JobActivity的filter按鈕點擊後編寫如下代碼:
public void onClick(View v) { switch (v.getId()) { //id為job_area_button的button是一所示的filter按鈕 case R.id.job_area_button: { Intent intent = new Intent(); //設定要跳轉的activity intent.setClass(this, AreaSelectActivity.class); //這句話很關鍵,就是之前我交代的兩個方法中的第一個,區別於startActivity方法的是,他告訴編譯器,我這個頁面是要接受下一個頁面的回傳值的。RESULT_CODE_AREASELECT是我自己寫的常量,大家可以用任何整型變數代替 startActivityForResult(intent, RESULT_CODE_AREASELECT); } break; }}
2.在AreaSelectActivity這個activity中點擊某個item後編寫如下代碼:
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { switch (parent.getId()) { //這個id位area_all_listview的是AreaSelectActivity的listview case R.id.area_all_listview: { Intent intent = new Intent(this,JobActivity.class); intent.putExtra("position", position); //關鍵是這句話,他告訴前一個activity(也就是JobActivity)我這邊設定了一個tag,RESULT_OK,用來區分是哪一個activity傳遞過來的值(因為可以JobActivity可能要接受多個activity的回傳值) setResult(RESULT_OK, intent); this.finish(); } break; }}
3.在JobActivity中接受回傳值:
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (JobActivity.RESULT_CODE_AREASELECT == requestCode) { if (null == data) { return; } int position = data.getIntExtra("position", 0); System.out.println("postion:" + position); }}
先解釋一下onActivityResult中的幾個參數的意思吧,
(1)requestCode:不言而喻,就是請求碼,也就是我之前設定的常量RESULT_CODE_AREASELECT
(2)resultCode:不多說,就是返回碼,也就是RESULT_OK了
(3)data:傳過來的資料,使用intent封裝好的。
所以呢,我們就先判斷這個請求碼是不是
JobActivity.RESULT_CODE_AREASELECT
如果是的話,就說明是AreaSelectActivity回傳回來的,那我們的邏輯就在裡面寫了。取到裡面的intent中的position即可。
好了,所有的傳值方法都介紹完畢了,好累啊,歡迎大家多多交流!