基于LiveData和ViewModel的路线管理实现(带PopupWindow删除功能)
包含RecyclerView绑定、PopupWindow删除功能和SharedPreferences持久化存储。
1. RouteInfo类(实现Parcelable接口)
java
复制
下载
import android.os.Parcel; import android.os.Parcelable;public class RouteInfo implements Parcelable {private Integer routeID;private Integer routeState;private String name;private String mapInfo; // 简化存储private String routeTraceFilePath;private Double routeLength;private String routeBeginPhoto;private String routeEndPhoto;private Integer routeTimeCost;private int routeThumbnailImgPath;// 构造方法public RouteInfo() {}protected RouteInfo(Parcel in) {routeID = in.readInt();routeState = in.readInt();name = in.readString();mapInfo = in.readString();routeTraceFilePath = in.readString();routeLength = in.readDouble();routeBeginPhoto = in.readString();routeEndPhoto = in.readString();routeTimeCost = in.readInt();routeThumbnailImgPath = in.readInt();}public static final Creator<RouteInfo> CREATOR = new Creator<RouteInfo>() {@Overridepublic RouteInfo createFromParcel(Parcel in) {return new RouteInfo(in);}@Overridepublic RouteInfo[] newArray(int size) {return new RouteInfo[size];}};// Getter和Setter方法public Integer getRouteID() { return routeID; }public void setRouteID(Integer routeID) { this.routeID = routeID; }// 其他getter/setter省略...@Overridepublic int describeContents() { return 0; }@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(routeID);dest.writeInt(routeState);dest.writeString(name);dest.writeString(mapInfo);dest.writeString(routeTraceFilePath);dest.writeDouble(routeLength);dest.writeString(routeBeginPhoto);dest.writeString(routeEndPhoto);dest.writeInt(routeTimeCost);dest.writeInt(routeThumbnailImgPath);} }
2. ViewModel类(管理路线数据)
java
复制
下载
import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; import java.util.ArrayList; import java.util.List;public class RouteViewModel extends ViewModel {private MutableLiveData<List<RouteInfo>> routeListLiveData;private List<RouteInfo> routeList = new ArrayList<>();public LiveData<List<RouteInfo>> getRouteList() {if (routeListLiveData == null) {routeListLiveData = new MutableLiveData<>();loadRoutes();}return routeListLiveData;}private void loadRoutes() {// 这里可以从SharedPreferences加载数据routeListLiveData.setValue(new ArrayList<>(routeList));}public void addRoute(RouteInfo route) {routeList.add(route);routeListLiveData.setValue(new ArrayList<>(routeList));}public void deleteRoute(int position) {if (position >= 0 && position < routeList.size()) {routeList.remove(position);routeListLiveData.setValue(new ArrayList<>(routeList));}} }
3. SharedPreferences工具类
java
复制
下载
import android.content.Context; import android.content.SharedPreferences; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List;public class RoutePrefsUtil {private static final String PREFS_NAME = "route_prefs";private static final String ROUTE_LIST_KEY = "route_list";public static void saveRoutes(Context context, List<RouteInfo> routes) {SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);SharedPreferences.Editor editor = prefs.edit();Gson gson = new Gson();String json = gson.toJson(routes);editor.putString(ROUTE_LIST_KEY, json);editor.apply();}public static List<RouteInfo> loadRoutes(Context context) {SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);String json = prefs.getString(ROUTE_LIST_KEY, null);if (json == null) return new ArrayList<>();Gson gson = new Gson();Type type = new TypeToken<ArrayList<RouteInfo>>() {}.getType();return gson.fromJson(json, type);} }
4. RecyclerView Adapter(带PopupWindow)
java
复制
下载
import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.PopupWindow; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import java.util.List;public class RouteListAdapter extends RecyclerView.Adapter<RouteListAdapter.RouteViewHolder> {private List<RouteInfo> routeList;private OnRouteClickListener listener;private Context context;public interface OnRouteClickListener {void onRouteClick(int position);void onDeleteClick(int position);}public RouteListAdapter(Context context, List<RouteInfo> routeList, OnRouteClickListener listener) {this.context = context;this.routeList = routeList;this.listener = listener;}@NonNull@Overridepublic RouteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_route, parent, false);return new RouteViewHolder(view);}@Overridepublic void onBindViewHolder(@NonNull RouteViewHolder holder, int position) {RouteInfo route = routeList.get(position);holder.tvRouteName.setText(route.getName());holder.tvRouteLength.setText(String.format("%.2f 米", route.getRouteLength()));holder.ivMore.setOnClickListener(v -> showPopupWindow(v, position));}private void showPopupWindow(View anchorView, int position) {View popupView = LayoutInflater.from(context).inflate(R.layout.popup_route_options, null);PopupWindow popupWindow = new PopupWindow(popupView,ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT,true);popupView.findViewById(R.id.btn_delete).setOnClickListener(v -> {listener.onDeleteClick(position);popupWindow.dismiss();});popupWindow.showAsDropDown(anchorView);}@Overridepublic int getItemCount() {return routeList.size();}static class RouteViewHolder extends RecyclerView.ViewHolder {TextView tvRouteName;TextView tvRouteLength;ImageView ivMore;public RouteViewHolder(@NonNull View itemView) {super(itemView);tvRouteName = itemView.findViewById(R.id.tv_route_name);tvRouteLength = itemView.findViewById(R.id.tv_route_length);ivMore = itemView.findViewById(R.id.iv_more);}} }
5. 在Activity/Fragment中使用
java
复制
下载
import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.List;public class RouteListActivity extends AppCompatActivity {private RouteViewModel viewModel;private RouteListAdapter adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_route_list);RecyclerView recyclerView = findViewById(R.id.recycler_view);recyclerView.setLayoutManager(new LinearLayoutManager(this));viewModel = new ViewModelProvider(this).get(RouteViewModel.class);// 从SharedPreferences加载数据List<RouteInfo> savedRoutes = RoutePrefsUtil.loadRoutes(this);if (!savedRoutes.isEmpty()) {viewModel.getRouteList().observe(this, routes -> {adapter = new RouteListAdapter(this, routes, new RouteListAdapter.OnRouteClickListener() {@Overridepublic void onRouteClick(int position) {// 处理路线点击}@Overridepublic void onDeleteClick(int position) {viewModel.deleteRoute(position);RoutePrefsUtil.saveRoutes(RouteListActivity.this, viewModel.getRouteList().getValue());}});recyclerView.setAdapter(adapter);});for (RouteInfo route : savedRoutes) {viewModel.addRoute(route);}}} }
6. 布局文件
item_route.xml (RecyclerView item布局)
xml
复制
下载
运行
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:padding="16dp"><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:orientation="vertical"><TextViewandroid:id="@+id/tv_route_name"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="16sp"/><TextViewandroid:id="@+id/tv_route_length"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="14sp"/></LinearLayout><ImageViewandroid:id="@+id/iv_more"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@android:drawable/ic_menu_more"android:padding="8dp"/> </LinearLayout>
popup_route_options.xml (PopupWindow布局)
xml
复制
下载
运行
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"android:background="@android:color/white"android:elevation="8dp"><Buttonandroid:id="@+id/btn_delete"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="删除路线"android:minWidth="120dp"android:background="?attr/selectableItemBackground"/> </LinearLayout>
实现说明
-
数据管理:使用ViewModel管理路线数据,LiveData实现数据观察
-
持久化存储:通过SharedPreferences保存路线列表,使用Gson进行序列化
-
删除功能:通过PopupWindow实现删除按钮,点击后从列表移除并更新存储
-
UI更新:RecyclerView自动响应数据变化
使用时请确保在build.gradle中添加了必要的依赖:
gradle
复制
下载
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.3.1' implementation 'androidx.lifecycle:lifecycle-livedata:2.3.1' implementation 'com.google.code.gson:gson:2.8.6'