Android开发:如何实现将用户信息持久化展示在第二个Tab的列表中?
Got it, let's work through this problem together. You want two tabs: the first for inputting personal info, and the second to display all historical submissions (no data loss when switching tabs or restarting the app). It sounds like ListView didn't work out because you might have missed handling data persistence or dynamic updates properly. Let's fix this with a solid implementation using TabLayout, ViewPager2, RecyclerView, and shared preferences for persistence.
Step 1: Set Up the Main Tab Layout
First, create your main activity layout with TabLayout and ViewPager2 to manage the two tabs:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.google.android.material.tabs.TabLayout android:id="@+id/tabLayout" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabMode="fixed" app:tabGravity="fill"> <com.google.android.material.tabs.TabItem android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Input Info"/> <com.google.android.material.tabs.TabItem android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="History"/> </com.google.android.material.tabs.TabLayout> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
Step 2: Implement Tab 1 (Input Fragment)
We'll expand your existing XML to add a submit button, then write the fragment logic to save data when submitted.
Tab 1 Layout (fragment_input.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="vertical" android:padding="16dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:orientation="horizontal"> <TextView android:layout_width="150dp" android:layout_height="50dp" android:text="Name" android:textColor="#9e3d7f" android:textSize="17sp" android:textStyle="bold"/> <EditText android:id="@+id/edittxt_name" android:layout_width="0dp" android:layout_height="50dp" android:layout_weight="1" android:hint="Enter your name"/> </LinearLayout> <!-- Add more input fields here (email, phone, etc.) if needed --> <Button android:id="@+id/btn_submit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="32dp" android:text="Submit Info"/> </LinearLayout>
Tab 1 Fragment Code (InputFragment.kt)
import android.content.Context import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.EditText import androidx.fragment.app.Fragment import com.google.gson.Gson import com.google.gson.reflect.TypeToken class InputFragment : Fragment() { private lateinit var etName: EditText private lateinit var btnSubmit: Button override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_input, container, false) etName = view.findViewById(R.id.edittxt_name) btnSubmit = view.findViewById(R.id.btn_submit) btnSubmit.setOnClickListener { val userName = etName.text.toString().trim() if (userName.isNotEmpty()) { saveUserInfo(userName) etName.text.clear() // Notify HistoryFragment to refresh data (activity as MainActivity).refreshHistory() } } return view } private fun saveUserInfo(name: String) { val sharedPref = requireActivity().getSharedPreferences("UserHistory", Context.MODE_PRIVATE) val gson = Gson() val existingList = getExistingUserList(sharedPref, gson) existingList.add(name) val editor = sharedPref.edit() editor.putString("users", gson.toJson(existingList)) editor.apply() } private fun getExistingUserList(sharedPref: android.content.SharedPreferences, gson: Gson): MutableList<String> { val json = sharedPref.getString("users", null) return if (json != null) { val type = object : TypeToken<MutableList<String>>() {}.type gson.fromJson(json, type) } else { mutableListOf() } } }
Step 3: Implement Tab 2 (History Fragment)
We'll use RecyclerView here (it's more flexible for dynamic updates than ListView) to display all historical entries.
Tab 2 Layout (fragment_history.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:padding="16dp"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_user_history" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
RecyclerView Adapter (UserHistoryAdapter.kt)
import android.view.LayoutInflater import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView class UserHistoryAdapter(private val userList: List<String>) : RecyclerView.Adapter<UserHistoryAdapter.UserViewHolder>() { class UserViewHolder(itemView: android.view.View) : RecyclerView.ViewHolder(itemView) { val tvUserName: TextView = itemView.findViewById(android.R.id.text1) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder { val view = LayoutInflater.from(parent.context) .inflate(android.R.layout.simple_list_item_1, parent, false) return UserViewHolder(view) } override fun onBindViewHolder(holder: UserViewHolder, position: Int) { holder.tvUserName.text = userList[position] } override fun getItemCount(): Int = userList.size }
Tab 2 Fragment Code (HistoryFragment.kt)
import android.content.Context import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.gson.Gson import com.google.gson.reflect.TypeToken class HistoryFragment : Fragment() { private lateinit var rvHistory: RecyclerView private lateinit var adapter: UserHistoryAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_history, container, false) rvHistory = view.findViewById(R.id.rv_user_history) rvHistory.layoutManager = LinearLayoutManager(requireContext()) loadHistoryData() return view } fun loadHistoryData() { val sharedPref = requireActivity().getSharedPreferences("UserHistory", Context.MODE_PRIVATE) val gson = Gson() val json = sharedPref.getString("users", null) val userList = if (json != null) { val type = object : TypeToken<MutableList<String>>() {}.type gson.fromJson(json, type) } else { mutableListOf() } adapter = UserHistoryAdapter(userList) rvHistory.adapter = adapter } }
Step 4: Connect Tabs in Main Activity
Finally, set up the ViewPager2 adapter in your main activity to link the two fragments:
import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.viewpager2.adapter.FragmentStateAdapter import com.google.android.material.tabs.TabLayoutMediator class MainActivity : AppCompatActivity() { private lateinit var viewPager: androidx.viewpager2.widget.ViewPager2 private lateinit var historyFragment: HistoryFragment override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewPager = findViewById(R.id.viewPager) val tabLayout = findViewById<com.google.android.material.tabs.TabLayout>(R.id.tabLayout) viewPager.adapter = object : FragmentStateAdapter(this) { override fun getItemCount(): Int = 2 override fun createFragment(position: Int): androidx.fragment.app.Fragment { return when (position) { 0 -> InputFragment() 1 -> { historyFragment = HistoryFragment() historyFragment } else -> InputFragment() } } } TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = when (position) { 0 -> "Input Info" 1 -> "History" else -> "" } }.attach() } // Call this to refresh history after submission fun refreshHistory() { historyFragment.loadHistoryData() } }
Why This Works Better Than ListView
- Data Persistence: We use
SharedPreferences(with Gson to store lists) to save all submissions, so data stays even if the app restarts. - Dynamic Updates: The
refreshHistory()method tells the HistoryFragment to reload data and update the RecyclerView immediately after submission. - Flexibility: RecyclerView is more efficient for dynamic lists and supports more customization than ListView.
内容的提问来源于stack exchange,提问作者wasilikoslow

