Android Bundle 传递ArrayList<Object>的两种方法

Parcelable与Serializable在Android中对象序列化的应用
本文深入探讨了在Android开发中如何利用Parcelable和Serializable两种方式实现对象序列化,通过实例演示了如何在Bundle中存储和获取对象。

eg. 传递 ArrayList<Group> groups


一:将对象定义成 Parcelable 类型
   

public class Group implements Parcelable{

}

in:

 Bundle b = new Bundle();
 b.putParcelableArrayList("list",groups);

out:

ArrayList<Group> groups = b.getParcelableArrayList("list");

二,将对象定义成 Serializable 类型

public class Group implements Serializable{

}

in:

Bundle b = new Bundle();
b.putSerializable("list", groups);

out:

ArrayList<Group> groups = (ArrayList<Group>) b.getSerializable("list");


package com.example.kucun2.entity.data; import android.os.Handler; import android.os.Looper; import android.util.Log; import com.example.kucun2.entity.Information; import com.example.kucun2.entity.User; import com.example.kucun2.function.MyAppFunction; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import okhttp3.*; import java.io.IOException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Map; /** * 重构版API客户端 - 更灵活的类型处理 * 主要改进: * 1. 分离请求参数类型和响应类型 * 2. 支持多种请求方法(GET/POST/PUT/DELETE) * 3. 支持表单和JSON两种请求格式 * 4. 自动推导响应类型 * 5. 统一的请求执行流程 */ public class ApiClient { private static final Gson gson = GsonFactory.createGson(); private static final String TAG = "ApiClient"; private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private static final int MAX_RETRY = 3; private static final Handler MAIN_HANDLER = new Handler(Looper.getMainLooper()); // ====================== 核心请求方法 ====================== /** * 执行API请求(核心方法) * @param request 构建好的OkHttp请求 * @param responseType 期望的响应类型 * @param callback 回调接口 * @param <R> 响应数据类型 */ public static <R> void executeRequest(Request request, Type responseType, ApiCallback<R> callback) { OkHttpClient client = MyAppFunction.getClient(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { handleFailure(call, e, callback, 0); } @Override public void onResponse(Call call, Response response) throws IOException { handleResponse(response, responseType, callback); } }); } // ====================== 请求构建方法 ====================== /** * 构建JSON请求 * @param url API地址 * @param method 请求方法("POST", "PUT", "DELETE") * @param requestData 请求数据对象 * @return 构建好的Request对象 */ public static Request buildJsonRequest(String url, String method, Object requestData) { String jsonRequest = ReflectionJsonUtils.toJson(requestData); Log.d(TAG, method + " URL: " + url); Log.d(TAG, "请求数据: " + jsonRequest); RequestBody body = RequestBody.create(JSON, jsonRequest); return new Request.Builder() .url(url) .method(method, body) .build(); } /** * 构建表单请求 * @param url API地址 * @param method 请求方法 * @param formData 表单数据 * @return 构建好的Request对象 */ public static Request buildFormRequest(String url, String method, Map<String, String> formData) { FormBody.Builder builder = new FormBody.Builder(); for (Map.Entry<String, String> entry : formData.entrySet()) { builder.add(entry.getKey(), entry.getValue()); } Log.d(TAG, method + " URL: " + url); Log.d(TAG, "表单数据: " + formData); return new Request.Builder() .url(url) .method(method, builder.build()) .build(); } // ====================== 响应处理方法 ====================== private static <R> void handleResponse(Response response, Type responseType, ApiCallback<R> callback) throws IOException { try (ResponseBody responseBody = response.body()) { if (!response.isSuccessful()) { String error = "HTTP " + response.code() + ": " + response.message(); Log.e(TAG, error); notifyError(callback, response.code(), error); return; } String jsonResponse = responseBody.string(); Log.d(TAG, "服务器响应: " + jsonResponse); // 解析服务端的Information包装 Information<R> wrapper = gson.fromJson(jsonResponse, responseType); if (wrapper != null && wrapper.getStatus() == 200) { notifySuccess(callback, wrapper.getData()); } else { String errorMsg = wrapper != null ? "服务端错误: " + wrapper.getStatus() + " - " + wrapper.getText() : "无效的响应格式"; Log.e(TAG, errorMsg); notifyError(callback, wrapper != null ? wrapper.getStatus() : -1, errorMsg); } } catch (Exception e) { Log.e(TAG, "响应处理异常: " + e.getMessage()); notifyError(callback, -2, "数据处理异常: " + e.getMessage()); } } // ====================== 失败处理与重试 ====================== private static <R> void handleFailure(Call call, IOException e, ApiCallback<R> callback, int retryCount) { if (retryCount < MAX_RETRY) { Log.w(TAG, "请求失败,第" + (retryCount + 1) + "次重试: " + e.getMessage()); MAIN_HANDLER.postDelayed(() -> { call.clone().enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { handleFailure(call, e, callback, retryCount + 1); } @Override public void onResponse(Call call, Response response) throws IOException { handleResponse(response, getResponseType(callback), callback); } }); }, 2000); } else { Log.e(TAG, "最终请求失败: " + e.getMessage()); notifyError(callback, -1, "网络请求失败: " + e.getMessage()); } } // ====================== 类型处理工具 ====================== /** * 获取响应类型(通过回调接口的泛型参数) */ private static <R> Type getResponseType(ApiCallback<R> callback) { if (callback == null) { return new TypeToken<Information<Object>>(){}.getType(); } // 尝试获取泛型类型 Type[] genericInterfaces = callback.getClass().getGenericInterfaces(); for (Type type : genericInterfaces) { if (type instanceof ParameterizedType) { ParameterizedType pType = (ParameterizedType) type; if (pType.getRawType().equals(ApiCallback.class)) { Type dataType = pType.getActualTypeArguments()[0]; return TypeToken.getParameterized(Information.class, dataType).getType(); } } } // 默认返回Object类型 Log.w(TAG, "无法确定响应类型,使用默认Object类型"); return new TypeToken<Information<Object>>(){}.getType(); } // ====================== 回调通知方法 ====================== private static <R> void notifySuccess(ApiCallback<R> callback, R data) { if (callback != null) { MAIN_HANDLER.post(() -> callback.onSuccess(data)); } } private static <R> void notifyError(ApiCallback<R> callback, int code, String error) { if (callback != null) { MAIN_HANDLER.post(() -> callback.onError(code, error)); } } // ====================== 专用API方法 ====================== /** * 执行JSON API请求 * @param url API地址 * @param method 请求方法 * @param requestData 请求数据 * @param callback 回调接口 * @param <T> 请求数据类型 * @param <R> 响应数据类型 */ public static <T, R> void jsonRequest(String url, String method, T requestData, ApiCallback<R> callback) { Request request = buildJsonRequest(url, method, requestData); executeRequest(request, getResponseType(callback), callback); } /** * 执行表单API请求 * @param url API地址 * @param method 请求方法 * @param formData 表单数据 * @param callback 回调接口 * @param <R> 响应数据类型 */ public static <R> void formRequest(String url, String method, Map<String, String> formData, ApiCallback<R> callback) { Request request = buildFormRequest(url, method, formData); executeRequest(request, getResponseType(callback), callback); } // ====================== 便捷方法 ====================== public static <T, R> void postJson(String url, T data, ApiCallback<R> callback) { jsonRequest(url, "POST", data, callback); } public static <T, R> void putJson(String url, T data, ApiCallback<R> callback) { jsonRequest(url, "PUT", data, callback); } public static <T, R> void deleteJson(String url, T data, ApiCallback<R> callback) { jsonRequest(url, "DELETE", data, callback); } public static <R> void get(String url, ApiCallback<R> callback) { Request request = new Request.Builder().url(url).get().build(); executeRequest(request, getResponseType(callback), callback); } // ====================== 登录专用方法 ====================== public static void login(String username, String password, LoginCallback callback) { String url = MyAppFunction.getApiUrl("url_login"); Log.d(TAG, "login: " + url); formRequest(url, "POST", Map.of( "andy", username, "pass", password ), new ApiCallback<User>() { @Override public void onSuccess(User user) { if (callback != null) callback.onSuccess(user); } @Override public void onError(int statusCode, String error) { if (callback != null) callback.onFailure(error); } }); } // ====================== 回调接口定义 ====================== public interface ApiCallback<T> { void onSuccess(T data); void onError(int statusCode, String error); } public interface LoginCallback { void onSuccess(User user); void onFailure(String error); } } package com.example.kucun2.entity.data; import android.util.Log; import com.example.kucun2.function.MyAppFunction; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 可同步实体基类 * 提供实体到服务端的同步功能,包含自动重试机制和线程管理 */ public abstract class SynchronizableEntity implements EntityClassGrassrootsid { private static final String TAG = "SynchronizableEntity"; // 双重缓存结构:外层缓存类名,内层缓存字段名->Field对象 private static final Map<Class<?>, Map<String, Field>> CLASS_FIELD_CACHE = new HashMap<>(); // 网络请求线程池(静态共享) private static final ExecutorService NETWORK_EXECUTOR = Executors.newFixedThreadPool(4); /** * 获取指定类型操作的端点URL * * @param type 操作类型(如"create", "update", "delete"等) * @return 完整的端点URL路径 * * @apiNote 该方法通过资源键名拼接规则查找对应的URL资源 * @example 对于Product类的create操作,查找键为:"url_create_product" */ public String getEndpoint(String type) { // 构建资源键名:url_操作类型_类名小写 String key = "url_" + type + "_" + this.getClass().getSimpleName().toLowerCase(); return MyAppFunction.getApiUrl(key); } //================ 核心同步方法 ================// /** * 同步实体到服务端(公开接口) * * @param type 操作类型(如"add", "update","select","detect","all"等) * @param callback 同步结果回调接口 * * @implNote 内部调用私有方法实现带重试机制的同步 * @see #sync(String, SyncCallback, int) */ public void sync(String type, SyncCallback callback) { sync(type, callback, 0); // 初始重试次数为0 } private <T extends SynchronizableEntity> ApiClient.ApiCallback<T> getApiCallback(String type,SyncCallback callback,int retryCount,T thistype){ return new ApiClient.ApiCallback<T>() { @Override public void onSuccess(T responseData) { handleSyncSuccess(responseData, callback); } @Override public void onError(int statusCode, String error) { Log.d(TAG, "onError: "+thistype); handleSyncError(type, statusCode, error, callback, retryCount); } }; } private <T extends SynchronizableEntity> ApiClient.ApiCallback<T> getApiCallbackList(String type,SyncCallback callback,int retryCount,T thistype){ return new ApiClient.ApiCallback<T>() { @Override public void onSuccess(T responseData) { handleSyncSuccess(responseData, callback); } @Override public void onError(int statusCode, String error) { handleSyncError(type, statusCode, error, callback, retryCount); } }; } /** * 带重试机制的同步实现(私有方法) * * @param type 操作类型 * @param callback 同步结果回调 * @param retryCount 当前重试次数 * * @implSpec 1. 构建完整端点URL * 2. 通过线程池提交网络请求 * 3. 处理成功/失败回调 */ private void sync(String type, SyncCallback callback, int retryCount) { // 构建完整端点URL String endpoint =getEndpoint(type); Log.d(TAG, "同步端点: " + endpoint + ", 重试次数: " + retryCount); // 提交到线程池执行网络请求 NETWORK_EXECUTOR.execute(() -> { ApiClient.postJson(endpoint, this, getApiCallback(type,callback,retryCount,this)); }); } /** * 处理同步成功结果 * * @param responseData 服务端返回的实体数据 * @param callback 同步结果回调 * * @implNote 1. 更新实体ID * 2. 记录成功日志 * 3. 触发成功回调 */ private void handleSyncSuccess(SynchronizableEntity responseData, SyncCallback callback) { // 更新实体ID(如果服务端返回了新ID) if (responseData != null) { setId(responseData.getId()); Log.i(TAG, "同步成功, 新ID: " + responseData.getId()); } // 触发成功回调 if (callback != null) callback.onSyncSuccess(this); } /** * 处理同步错误(含重试逻辑) * * @param type 操作类型 * @param statusCode HTTP状态码(-1表示网络错误) * @param error 错误信息 * @param callback 同步结果回调 * @param retryCount 当前重试次数 * * @implSpec 1. 判断错误是否可重试(网络错误或5xx服务错误) * 2. 满足条件时进行指数退避重试 * 3. 达到最大重试次数后触发失败回调 * * @algorithm 使用指数退避算法:延迟时间 = 1000ms * 2^重试次数 */ private void handleSyncError(String type, int statusCode, String error, SyncCallback callback, int retryCount) { Log.e(TAG, "同步失败: " + error + ", 状态码: " + statusCode); // 判断是否可重试(网络错误或服务端5xx错误) boolean canRetry = statusCode == -1 || (statusCode >= 500 && statusCode < 600); // 满足重试条件(可重试错误且未达到最大重试次数) if (canRetry && retryCount < 3) { // 计算指数退避延迟时间 long delay = (long) (1000 * Math.pow(2, retryCount)); Log.w(TAG, "将在 " + delay + "ms 后重试"); try { // 当前线程休眠指定时间 Thread.sleep(delay); } catch (InterruptedException e) { // 恢复中断状态 Thread.currentThread().interrupt(); } // 递归调用进行重试(重试次数+1) sync(type, callback, retryCount + 1); } else { // 不可重试或达到最大重试次数,触发失败回调 if (callback != null) { String finalError = "同步失败: " + error; if (canRetry) finalError += " (重试失败)"; callback.onSyncFailure(finalError); } } } // 线程安全的对象复制方法 public void updateFrom(Object source) { if ( source == null) return; Class<?> targetClass = this.getClass(); Class<?> sourceClass = source.getClass(); // 获取或创建字段缓存 Map<String, Field> targetFields = getOrCreateFieldCache(targetClass); Map<String, Field> sourceFields = getOrCreateFieldCache(sourceClass); // 遍历源对象字段 for (Map.Entry<String, Field> entry : sourceFields.entrySet()) { String fieldName = entry.getKey(); Field sourceField = entry.getValue(); // 查找目标对象对应字段 Field targetField = targetFields.get(fieldName); if (targetField != null) { // 类型兼容性检查 if (isCompatibleTypes(sourceField.getType(), targetField.getType())) { try { // 复制字段值 Object value = sourceField.get(source); targetField.set(this, value); } catch (IllegalAccessException e) { // 处理异常,记录日志 } } } } } // 获取或创建类的字段缓存 private static Map<String, Field> getOrCreateFieldCache(Class<?> clazz) { // 双重检查锁确保线程安全 if (!CLASS_FIELD_CACHE.containsKey(clazz)) { synchronized (clazz) { if (!CLASS_FIELD_CACHE.containsKey(clazz)) { Map<String, Field> fieldMap = new HashMap<>(); // 递归获取所有字段(包括父类) for (Class<?> current = clazz; current != null; current = current.getSuperclass()) { for (Field field : current.getDeclaredFields()) { field.setAccessible(true); // 突破访问限制 fieldMap.put(field.getName(), field); } } CLASS_FIELD_CACHE.put(clazz, fieldMap); } } } return CLASS_FIELD_CACHE.get(clazz); } // 类型兼容性检查(支持自动装箱/拆箱) private static boolean isCompatibleTypes(Class<?> sourceType, Class<?> targetType) { // 处理基本类型和包装类的兼容性 if (sourceType.isPrimitive()) { sourceType = primitiveToWrapper(sourceType); } if (targetType.isPrimitive()) { targetType = primitiveToWrapper(targetType); } return targetType.isAssignableFrom(sourceType); } // 基本类型转包装类 private static Class<?> primitiveToWrapper(Class<?> primitiveType) { if (boolean.class.equals(primitiveType)) return Boolean.class; if (byte.class.equals(primitiveType)) return Byte.class; if (char.class.equals(primitiveType)) return Character.class; if (double.class.equals(primitiveType)) return Double.class; if (float.class.equals(primitiveType)) return Float.class; if (int.class.equals(primitiveType)) return Integer.class; if (long.class.equals(primitiveType)) return Long.class; if (short.class.equals(primitiveType)) return Short.class; if (void.class.equals(primitiveType)) return Void.class; return primitiveType; } //================ 回调接口 ================// /** * 同步操作回调接口 * * @implNote 使用方需实现此接口处理同步结果 */ public interface SyncCallback { /** * 同步成功回调 * * @param entity 同步后的实体对象(已更新ID) */ void onSyncSuccess(SynchronizableEntity entity); /** * 同步失败回调 * * @param error 失败原因描述 */ void onSyncFailure(String error); } } package com.example.kucun2.DataPreserver; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.util.Log; import com.example.kucun2.entity.*; import com.example.kucun2.entity.Information; import com.example.kucun2.entity.data.*; import com.example.kucun2.function.MyAppFunction; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.List; /** * 重构后的数据加载器:使用ApiClient处理网络请求 */ public class DataLoader { private static final String TAG = "DataLoader"; private final DataStore dataStore; private final DataAssociator dataAssociator; // private final DataPreserver dataPreserver; public DataLoader(DataStore dataStore, DataAssociator dataAssociator ) { this.dataStore = dataStore; this.dataAssociator = dataAssociator; // this.dataPreserver = dataPreserver; } public void loadAllData(Context context, LoadDataCallback callback) { if (Looper.myLooper() != Looper.getMainLooper()) { throw new IllegalStateException("必须在主线程调用Data.loadAllData"); } // dataPreserver.ensurePreservedObjects(); String url = MyAppFunction.getApiUrl("url_all"); Log.d(TAG, "开始加载数据, URL: " + url); // 使用ApiClient的get方法发送请求 ApiClient.get(url, new ApiClient.ApiCallback<DataLoader.AllDataResponse>() { @Override public void onSuccess(AllDataResponse allData) { Log.d(TAG, "数据加载成功"); parseAndAssignData(allData, callback); } @Override public void onError(int statusCode, String error) { Log.e(TAG, "数据加载失败: " + error + ", 状态码: " + statusCode); new Handler(Looper.getMainLooper()).post(callback::onFailure); } }); } private void parseAndAssignData(AllDataResponse allData, LoadDataCallback callback) { try { mergeAllLists(allData); dataAssociator.automaticAssociation(); callback.onSuccess(); } catch (Exception e) { Log.e(TAG, "数据处理异常: " + e.getMessage()); callback.onFailure(); } } private void mergeAllLists(AllDataResponse allData) { mergeList(dataStore.bancais, allData.bancais); mergeList(dataStore.caizhis, allData.caizhis); mergeList(dataStore.mupis, allData.mupis); mergeList(dataStore.chanpins, allData.chanpins); mergeList(dataStore.chanpin_zujians, allData.chanpin_zujians); mergeList(dataStore.dingdans, allData.dingdans); mergeList(dataStore.dingdan_chanpins, allData.dingdan_chanpins); mergeList(dataStore.dingdan_bancais, allData.dingdan_bancais); mergeList(dataStore.kucuns, allData.kucuns); mergeList(dataStore.zujians, allData.zujians); mergeList(dataStore.users, allData.users); mergeList(dataStore.jinhuos, allData.jinhuos); } private <T extends SynchronizableEntity> void mergeList( SynchronizedList<T> targetList, List<T> newList) { if (newList == null) return; targetList.mergeList(newList); } public interface LoadDataCallback { void onSuccess(); void onFailure(); } public static class AllDataResponse { public List<Bancai> bancais; public List<Caizhi> caizhis; public List<Mupi> mupis; public List<Chanpin> chanpins; public List<Chanpin_Zujian> chanpin_zujians; public List<Dingdan> dingdans; public List<Dingdan_Chanpin> dingdan_chanpins; public List<Dingdan_bancai> dingdan_bancais; public List<Kucun> kucuns; public List<Zujian> zujians; public List<User> users; public List<Jinhuo> jinhuos; } } package com.example.kucun2.ui.login; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.example.kucun2.DataPreserver.Data; import com.example.kucun2.MainActivity; import com.example.kucun2.R; import com.example.kucun2.entity.User; import com.example.kucun2.entity.data.ApiClient; public class LoginActivity extends AppCompatActivity { private EditText etUsername, etPassword; private CheckBox cbRemember, cbAutoLogin; private Button btnLogin; private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_loading); // 初始化视图 etUsername = findViewById(R.id.et_username); etPassword = findViewById(R.id.et_password); cbRemember = findViewById(R.id.cb_remember); cbAutoLogin = findViewById(R.id.cb_auto_login); btnLogin = findViewById(R.id.btn_login); progressBar = findViewById(R.id.progress_bar); // 设置登录按钮点击事件 btnLogin.setOnClickListener(v -> attemptLogin()); } private void attemptLogin() { String username = etUsername.getText().toString().trim(); String password = etPassword.getText().toString().trim(); if (username.isEmpty() || password.isEmpty()) { Toast.makeText(this, "用户名或密码不能为空", Toast.LENGTH_SHORT).show(); return; } // 显示进度条,禁用登录按钮 progressBar.setVisibility(View.VISIBLE); btnLogin.setEnabled(false); // 调用网络登录 ApiClient.login(username, password, new ApiClient.LoginCallback() { @Override public void onSuccess(User user) { runOnUiThread(() -> { progressBar.setVisibility(View.GONE); btnLogin.setEnabled(true); // 保存登录状态 saveLoginPreferences(username, password); // 设置当前用户 Data.setCurrentUser(user); // 跳转到主界面 startMainActivity(); }); } @Override public void onFailure(String error) { runOnUiThread(() -> { progressBar.setVisibility(View.GONE); btnLogin.setEnabled(true); Toast.makeText(LoginActivity.this, "登录失败: " + error, Toast.LENGTH_SHORT).show(); }); } }); } private void saveLoginPreferences(String username, String password) { // 在实际应用中,应使用加密方式存储密码 getSharedPreferences("login_prefs", MODE_PRIVATE).edit() .putString("username", username) .putString("password", password) .putBoolean("remember", cbRemember.isChecked()) .putBoolean("auto_login", cbAutoLogin.isChecked()) .apply(); } private void startMainActivity() { Intent intent = new Intent(this, MainActivity.class); startActivity(intent); finish(); // 关闭登录界面 } } ------------------------登录和获取初始数据的时候一点问题没有,只有通过基类传递时出错了------------------------------------ java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.example.kucun2.entity.data.SynchronizableEntity at com.example.kucun2.entity.data.SynchronizableEntity$1.onSuccess(SynchronizableEntity.java:56)
06-28
activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:layout_marginBottom="4dp" android:background="@color/gray" android:gravity="center_vertical"> <TextView android:id="@+id/tv_order" style="@style/tvNavigationBarStyle" android:text="点菜" android:textColor="@android:color/black" /> <TextView android:id="@+id/tv_discuss" style="@style/tvNavigationBarStyle" android:layout_toRightOf="@id/tv_order" android:text="评价" android:textColor="@color/dark_gray" /> <TextView android:id="@+id/tv_business" style="@style/tvNavigationBarStyle" android:layout_toRightOf="@id/tv_discuss" android:text="商家" android:textColor="@color/dark_gray" /> <TextView android:layout_width="70dp" android:layout_height="30dp" android:layout_alignParentRight="true" android:layout_marginRight="15dp" android:background="@drawable/friend_list" android:gravity="center" android:text="好友拼单" android:textColor="#ef842c" android:textSize="12sp" /> </RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <fragment android:id="@+id/left" android:name="cn.itcast.menu.LeftFragment" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" tools:layout="@layout/left_layout" /> <fragment android:id="@+id/right" android:name="cn.itcast.menu.RightFragment" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="3" tools:layout="@layout/right_layout" /> </LinearLayout> </LinearLayout> left_layout.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="match_parent" android:background="#f7f8f9" android:gravity="center_horizontal" android:orientation="vertical"> <TextView android:id="@+id/tv_recommend" style="@style/tvLeftStyle" android:text="推荐" android:background="@android:color/white"/> <TextView android:id="@+id/tv_must_buy" style="@style/tvLeftStyle" android:text="进店必买" /> </LinearLayout> list_item.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="match_parent" android:orientation="horizontal" android:padding="4dp"> <ImageView android:id="@+id/iv_img" android:layout_width="70dp" android:layout_height="70dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:orientation="vertical"> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="2dp" android:textColor="@android:color/black" android:textSize="14sp" /> <TextView android:id="@+id/tv_sale" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#868788" android:textSize="12sp" /> <TextView android:id="@+id/tv_price" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="2dp" android:textColor="#e85b4d" android:textSize="12sp" /> </LinearLayout> </LinearLayout> right_layout.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="match_parent" android:background="@android:color/white" android:orientation="vertical"> <ListView android:id="@+id/lv_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="@null"/> </LinearLayout> FoodBean.java package cn.itcast.menu; import java.io.Serializable; public class FoodBean implements Serializable { //序列化时保持FoodBean类版本的兼容性 private static final long serialVersionUID = 1L; private String name; //菜品名称 private String sales; //月售信息 private String price; //菜品价格 private int img; //菜品图片 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSales() { return sales; } public void setSales(String sales) { this.sales = sales; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } public int getImg() { return img; } public void setImg(int img) { this.img = img; } } LeftFragment.java import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class LeftFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view =inflater.inflate(R.layout.left_layout,container,false); return view; } @Override public void onPause() { super.onPause(); } } RightAdapter.java import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import java.util.List; public class RightAdapter extends BaseAdapter { private Context mContext; private List<FoodBean> list; public RightAdapter(Context context ,List<FoodBean> list) { this.mContext = context; this.list=list; } @Override public int getCount() { //获取列表条目的总数 return list.size(); //返回ListView 条目的总数 } @Override public Object getItem(int position) { return list.get(position); //返回列表条目的数据对象 } @Override public long getItemId(int position) { return position; //返回列表条目的id } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { convertView = View.inflate(mContext, R.layout.list_item, null); holder = new ViewHolder(); holder.tv_name = convertView.findViewById(R.id.tv_name); holder.tv_sale = convertView.findViewById(R.id.tv_sale); holder.tv_price = convertView.findViewById(R.id.tv_price); holder.iv_img = convertView.findViewById(R.id.iv_img); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } FoodBean bean=list.get(position); holder.tv_name.setText(bean.getName()); holder.tv_sale.setText(bean.getSales()); holder.tv_price.setText(bean.getPrice()); holder.iv_img.setBackgroundResource(bean.getImg()); return convertView; } class ViewHolder { TextView tv_name, tv_sale,tv_price; ImageView iv_img; } } RightFragment.java import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import java.io.Serializable; import java.util.List; public class RightFragment extends Fragment { private ListView lv_list; public RightFragment() { } public RightFragment getInstance(List<FoodBean> list) { RightFragment rightFragment = new RightFragment(); //通过Bundle对象传递数据可以保证在设备横竖屏切换时传递的数据不丢失 Bundle bundle = new Bundle(); //将需要传递的字符串以键值对的形式传入bundle对象 bundle.putSerializable("list", (Serializable) list); rightFragment.setArguments(bundle); return rightFragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.right_layout, container, false); lv_list = view.findViewById(R.id.lv_list); if (getArguments() != null) { List<FoodBean> list = (List<FoodBean>) getArguments(). getSerializable("list"); RightAdapter adapter = new RightAdapter(getActivity(), list); lv_list.setAdapter(adapter); } return view; } } MainActivity.java import android.app.FragmentManager; import android.app.FragmentTransaction; import android.graphics.Color; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.TextView; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MainActivity extends AppCompatActivity { private FragmentManager fragmentManager; private FragmentTransaction fragmentTransaction; private LeftFragment leftFragment; private TextView tv_recommend, tv_must_buy; private RightFragment rightFragment; //推荐菜单列表数据 private String[] names1 = {"爆款*肥牛鱼豆腐骨肉相连三荤五素一份米饭", "豪华双人套餐", "【热销】双人套餐(含两份米饭)"}; private String[] sales1 = {"月售520 好评度80%", "月售184 好评度68%", "月售114 好评度60%"}; private String[] prices1 = {"¥23", "¥41", "¥32"}; private int[] imgs1 = {R.drawable.recom_one, R.drawable.recom_two, R.drawable.recom_three}; //进店必买菜单列表数据 private String[] names2 = {"'蔬菜主义'1人套餐", "2人经典套餐", "3人经典套餐"}; private String[] sales2 = {"月售26 好评度70%", "月售12 好评度50%", "月售4 好评度40%"}; private String[] prices2 = {"¥44", "¥132", "¥180"}; private int[] imgs2 = {R.drawable.must_buy_one, R.drawable.must_buy_two, R.drawable.must_buy_three}; private Map<String,List<FoodBean>> map; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setData(); init(); clickEvent(); } private void init() { fragmentManager = getFragmentManager();//获取fragmentManager //通过findFragmentById()方法获取leftFragment leftFragment = (LeftFragment) fragmentManager.findFragmentById(R.id.left); //获取左侧菜单栏中的控件 tv_recommend = leftFragment.getView().findViewById(R.id.tv_recommend); tv_must_buy = leftFragment.getView().findViewById(R.id.tv_must_buy); } private void setData(){ map=new HashMap<>(); List<FoodBean> list1=new ArrayList<>(); List<FoodBean> list2=new ArrayList<>(); for (int i=0;i<names1.length;i++){ FoodBean bean=new FoodBean(); bean.setName(names1[i]); bean.setSales(sales1[i]); bean.setPrice(prices1[i]); bean.setImg(imgs1[i]); list1.add(bean); } map.put("1",list1);//将推荐菜单列表的数据添加到map集合中 for (int i=0;i<names2.length;i++){ FoodBean bean=new FoodBean(); bean.setName(names2[i]); bean.setSales(sales2[i]); bean.setPrice(prices2[i]); bean.setImg(imgs2[i]); list2.add(bean); } map.put("2",list2); //将进店必买菜单列表的数据添加到map集合中 } private void clickEvent() { tv_recommend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //调用switchData()方法填充Rightfragment中的数据 switchData(map.get("1")); tv_recommend.setBackgroundColor(Color.WHITE); tv_must_buy.setBackgroundResource(R.color.gray); } }); tv_must_buy.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { switchData(map.get("2")); tv_must_buy.setBackgroundColor(Color.WHITE); tv_recommend.setBackgroundResource(R.color.gray); } }); //设置首次进入界面后,默认需要显示的数据 switchData(map.get("1")); } /** * 填充Activity右侧的Fragment,并传递列表数据list */ public void switchData(List<FoodBean> list) { fragmentManager = getFragmentManager(); fragmentTransaction = fragmentManager.beginTransaction();//开启一个事务 //通过调用getInstance()方法实例化RightFragment rightFragment = new RightFragment().getInstance(list); //调用replace()方法 fragmentTransaction.replace(R.id.right, rightFragment); fragmentTransaction.commit(); } } 说明如何编写列表显示的代码
最新发布
11-08
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值