Android Java:如何在Fragment中实现带CardView的RecyclerView?
Hey there! I totally get where you're coming from—jumping into Android development after working with web/APIs can feel tricky, especially when tutorials don't live up to expectations. Let's walk through exactly how to build that event feed app using RecyclerView (for handling large JSON datasets efficiently) and CardView (for polished, modern UI).
First, make sure your app's build.gradle (Module level) has these dependencies. They're non-negotiable for what we're building:
dependencies { // RecyclerView for efficient list handling implementation "androidx.recyclerview:recyclerview:1.3.2" // CardView for styled, elevated list items implementation "androidx.cardview:cardview:1.0.0" // Gson for seamless JSON-to-object parsing implementation "com.google.code.gson:gson:2.10.1" // Retrofit for clean, maintainable API calls implementation "com.squareup.retrofit2:retrofit:2.9.0" implementation "com.squareup.retrofit2:converter-gson:2.9.0" }
Since you know APIs, this part should feel familiar. Let's say your API returns JSON like this:
{
"events": [
{
"id": 1,
"title": "Summer Music Festival",
"date": "2024-07-15",
"description": "A day of live music and food trucks"
}
]
}
Create a data class to map this JSON structure. Gson will handle the parsing automatically:
data class EventResponse( val events: List<Event> ) data class Event( val id: Int, val title: String, val date: String, val description: String )
First, create a layout for individual event items (item_event.xml) using CardView to wrap content for a polished look:
<?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" card_view:cardCornerRadius="8dp" card_view:cardElevation="4dp" card_view:cardUseCompatPadding="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/tv_event_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="18sp" android:textStyle="bold"/> <TextView android:id="@+id/tv_event_date" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" android:textColor="@android:color/darker_gray" android:layout_marginTop="4dp"/> <TextView android:id="@+id/tv_event_description" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="16sp" android:layout_marginTop="8dp"/> </LinearLayout> </androidx.cardview.widget.CardView>
Then add the RecyclerView to your main activity layout (activity_main.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"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view_events" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
This is the core of efficient list handling. The ViewHolder pattern ensures we reuse views instead of creating new ones for every item—critical for large datasets:
class EventAdapter(private val events: List<Event>) : RecyclerView.Adapter<EventAdapter.EventViewHolder>() { inner class EventViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val title: TextView = itemView.findViewById(R.id.tv_event_title) val date: TextView = itemView.findViewById(R.id.tv_event_date) val description: TextView = itemView.findViewById(R.id.tv_event_description) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EventViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_event, parent, false) return EventViewHolder(view) } override fun onBindViewHolder(holder: EventViewHolder, position: Int) { val event = events[position] holder.title.text = event.title holder.date.text = event.date holder.description.text = event.description } override fun getItemCount(): Int = events.size }
Now wire up the API call and feed data into the RecyclerView. First, create a Retrofit service interface:
interface EventApiService { @GET("events") suspend fun getEvents(): Response<EventResponse> }
Then in your MainActivity, set up Retrofit, fetch data, and attach the adapter:
class MainActivity : AppCompatActivity() { private lateinit var recyclerView: RecyclerView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) recyclerView = findViewById(R.id.recycler_view_events) recyclerView.layoutManager = LinearLayoutManager(this) // Fetch events from API using coroutines lifecycleScope.launch { try { val retrofit = Retrofit.Builder() .baseUrl("https://your-api-base-url.com/") // Replace with your actual API URL .addConverterFactory(GsonConverterFactory.create()) .build() val service = retrofit.create(EventApiService::class.java) val response = service.getEvents() if (response.isSuccessful) { val events = response.body()?.events ?: emptyList() recyclerView.adapter = EventAdapter(events) } else { Toast.makeText(this@MainActivity, "Failed to load events", Toast.LENGTH_SHORT).show() } } catch (e: Exception) { Toast.makeText(this@MainActivity, "Network error: ${e.message}", Toast.LENGTH_SHORT).show() } } } }
- Use DiffUtil: When updating the list (e.g., pull-to-refresh), replace
notifyDataSetChanged()with DiffUtil—it only updates changed items, boosting performance. - Image Loading: If events have images, use Glide or Picasso for efficient, cached image loading.
- Pagination: Implement load-more-on-scroll to avoid loading hundreds of events at once.
- Offline Caching: Add OkHttp caching to Retrofit to show cached data when the user is offline.
You've got this—since you already have API experience, the biggest learning curve is getting comfortable with Android's view system. Test each step one by one, and you'll have your event feed up and running in no time!
内容的提问来源于stack exchange,提问作者Lucas Arruda

