[Android] Activity之間如何透過Intent傳遞複雜結構的data
(How to add complex data to the intent object)
Application是由許多Activities所組成,不同Activity之間是藉由Intent物件來進行啟動/關閉,Intent物件可以帶入data傳遞給它所喚起的Activity,它可能是上個Activity執行後的結果。
在Intent object加入data最常見的方法即為putExtra(),它提供了多種overload方法,包含各種primitive data type以及其Array資料型態,另外它也支援實作Serializable與Parcelable兩種介面的資料型態。
當遇到需要傳遞較複雜的資料型態(自定義且putExtra沒有對應的多載函式)給即將開啟的Activity,例如:Custom list view's data source就常使用HashMap、ArrayList等資料型態的組合,這些都是實作Serializable常見的類別,此時就可以採用putExtra(String name, Serializable value)將資料帶入Intent object,接受端Activity再透過getSerializableExtra(String name)取得自定義的Serializable data,藉此達到傳遞複雜資料的目的。
以下將示範透過Intent將自定義資料型態ArrayList< HashMap>傳遞給Custom ListView作為其Adapter之資料來源。
程式碼說明
一、建立負責activate ListActivity之Activity
package com.intentdemo; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; public class IntentDemoActivity extends Activity { private int[] icons={ R.drawable.icon1,R.drawable.icon2, R.drawable.icon3,R.drawable.icon4, R.drawable.icon5,R.drawable.icon6 }; private String[] names={ "role1","role2", "role3","role4", "role5","role6" }; private String[] tels={ "000-11111","999-19191", "000-22222","919-49791", "101-33333","929-29391" }; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); } }
IntentDemoActivity.java
二、宣告自定義資料型態private ArrayList< HashMap< String,Object>> getListData(){ ArrayList dataSet = new ArrayList(); for(int i=0;i< 6;i++){ HashMap< String,Object> data = new HashMap< String,Object>(); data.put("icon", icons[i]); data.put("name", names[i]); data.put("tel", tels[i]); dataSet.add(data); } return dataSet; }三、按鈕click事件觸發Intent並附帶自定義data
public void onIntentButtonClick(View v){ Intent intent=new Intent(); intent.putExtra("listData", getListData()); intent.setClass(this, RoleListActivity.class); startActivity(intent); }四、Custom ListActivity透過getSerializableExtra()接收data並將其設為ListView Adapter資料來源
package com.intentdemo; import java.util.ArrayList; import java.util.HashMap; import android.app.ListActivity; import android.os.Bundle; public class RoleListActivity extends ListActivity { @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.role_list); //get intent data ArrayList< HashMap< String,Object>> data= (ArrayList< HashMap< String, Object>>)getIntent() .getSerializableExtra("listData"); this.setListAdapter(new ListAdapter(this,data)); } }
RoleListActivity.java
package com.intentdemo; import java.util.ArrayList; import java.util.HashMap; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; public class ListAdapter extends BaseAdapter { private ArrayList< hashmap> data; private LayoutInflater inflater; public ListAdapter(Context c,ArrayList< HashMap< String,Object>> d){ inflater=LayoutInflater.from(c); data=d; } @Override public int getCount() { return data.size(); } @Override public Object getItem(int index) { return data.get(index); } @Override public long getItemId(int index) { return index; } @Override public View getView(int i, View v, ViewGroup p) { ViewHolder holder; if(v==null){ v=inflater.inflate(R.layout.role_list_row, null); holder=new ViewHolder(); holder.icon=(ImageView)v.findViewById(R.id.icon); holder.nameTxt=(TextView)v.findViewById(R.id.name); holder.telTxt=(TextView)v.findViewById(R.id.tel); v.setTag(holder); }else{ holder=(ViewHolder)v.getTag(); } holder.icon.setImageResource((Integer)data.get(i).get("icon")); holder.nameTxt.setText((String)data.get(i).get("name")); holder.telTxt.setText((String)data.get(i).get("tel")); return v; } static class ViewHolder{ ImageView icon; TextView nameTxt; TextView telTxt; } }
ListAdapter.java
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
role_list.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="100dp" android:orientation="horizontal" > <ImageView android:id="@+id/icon" android:layout_width="90dp" android:layout_height="90dp" android:padding="5dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="vertical" > <TextView android:id="@+id/name" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="20sp" /> <TextView android:id="@+id/tel" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="20sp" /> </LinearLayout> </LinearLayout>
您好 ,板大
回覆刪除我遇到一個問題
Diy diy = new Diy();//自定義的物件
ArrayList dataSet = new ArrayList();
HashMap data = new HashMap();
data.put("物件名稱", diy);
dataSet.add(data);
Intent intent = new Intent();
intent.setClass(A.this, B.class);
intent.putExtra("傳送名稱", dataSet);
startActivityForResult(intent, 0); // 這行會出錯
不曉得是錯在哪?
望板大指點
請問錯誤訊息是?
回覆刪除startActivityForResult函式的第二個參數是什麼型態的變數?
08-22 13:23:17.124: D/libEGL(31448): loaded /system/lib/egl/libGLES_android.so
回覆刪除08-22 13:23:17.134: D/libEGL(31448): loaded /system/lib/egl/libEGL_adreno200.so
08-22 13:23:17.134: D/libEGL(31448): loaded /system/lib/egl/libGLESv1_CM_adreno200.so
08-22 13:23:17.144: D/libEGL(31448): loaded /system/lib/egl/libGLESv2_adreno200.so
08-22 13:23:17.184: D/OpenGLRenderer(31448): Enabling debug mode 0
08-22 13:23:34.270: D/libEGL(31543): loaded /system/lib/egl/libGLES_android.so
08-22 13:23:34.290: D/libEGL(31543): loaded /system/lib/egl/libEGL_adreno200.so
08-22 13:23:34.290: D/libEGL(31543): loaded /system/lib/egl/libGLESv1_CM_adreno200.so
08-22 13:23:34.300: D/libEGL(31543): loaded /system/lib/egl/libGLESv2_adreno200.so
08-22 13:23:34.370: D/OpenGLRenderer(31543): Enabling debug mode 0
08-22 13:24:03.989: D/AndroidRuntime(31543): Shutting down VM
08-22 13:24:03.989: W/dalvikvm(31543): threadid=1: thread exiting with uncaught exception (group=0x40aa9228)
08-22 13:24:04.009: E/AndroidRuntime(31543): FATAL EXCEPTION: main
08-22 13:24:04.009: E/AndroidRuntime(31543): java.lang.RuntimeException: Parcel: unable to marshal value com.example.test.Diy@40d83580
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Parcel.writeValue(Parcel.java:1137)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Parcel.writeMapInternal(Parcel.java:493)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Parcel.writeMap(Parcel.java:477)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Parcel.writeValue(Parcel.java:1068)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Parcel.writeList(Parcel.java:524)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Parcel.writeValue(Parcel.java:1097)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Parcel.writeMapInternal(Parcel.java:493)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Bundle.writeToParcel(Bundle.java:1612)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Parcel.writeBundle(Parcel.java:507)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.content.Intent.writeToParcel(Intent.java:6464)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:1673)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.app.Instrumentation.execStartActivity(Instrumentation.java:1505)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.app.Activity.startActivityForResult(Activity.java:3251)
08-22 13:24:04.009: E/AndroidRuntime(31543): at com.example.test.MainActivity$1.onClick(MainActivity.java:32)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.view.View.performClick(View.java:3549)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.view.View$PerformClick.run(View.java:14400)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Handler.handleCallback(Handler.java:605)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Handler.dispatchMessage(Handler.java:92)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.os.Looper.loop(Looper.java:154)
08-22 13:24:04.009: E/AndroidRuntime(31543): at android.app.ActivityThread.main(ActivityThread.java:4945)
08-22 13:24:04.009: E/AndroidRuntime(31543): at java.lang.reflect.Method.invokeNative(Native Method)
08-22 13:24:04.009: E/AndroidRuntime(31543): at java.lang.reflect.Method.invoke(Method.java:511)
08-22 13:24:04.009: E/AndroidRuntime(31543): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
08-22 13:24:04.009: E/AndroidRuntime(31543): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
08-22 13:24:04.009: E/AndroidRuntime(31543): at dalvik.system.NativeStart.main(Native Method)
startActivityForResult(Intent,int);主要是可以回傳資料用
回覆刪除如果沒有要回傳就用startActivity(Intent)即可,不過還是會出錯
原始碼
http://dl.dropbox.com/u/35125399/test.7z
我大概看了一下程式碼,出錯的地方不是在於傳的參數,應該是你要回傳值的Activity沒有宣告在Android.manifest裡,以上提供給你參考
回覆刪除You should make your com.example.test.Diy class implement Parcelable.
回覆刪除