[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並附帶自定義datapublic 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.
回覆刪除