Android基于Volley实现多Spinner联动(数据来自服务器JSON)
Hey there! Since you're new to Android development, let's break down exactly how to build this 3-spinner联动 feature with Volley—step by step, so it's easy to follow.
First, you need to include Volley in your project. Open your module-level build.gradle file and add this dependency:
dependencies { implementation 'com.android.volley:volley:1.2.1' }
Then, add the internet permission to your AndroidManifest.xml (Volley needs this to make network calls):
<uses-permission android:name="android.permission.INTERNET" />
To make handling JSON responses easier, create simple data classes to represent your job types, tasks, and prices. Here's a Kotlin example (Java works similarly—just use POJOs):
// Represents a job type (e.g., "Plumber") data class JobType(val id: String, val name: String) // We'll pair tasks and prices, so we can load them together data class TaskPrice(val taskName: String, val price: String)
Create a layout with three spinners in your activity XML (e.g., activity_main.xml):
<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"> <Spinner android:id="@+id/spinner_job_type" android:layout_width="match_parent" android:layout_height="wrap_content" android:prompt="@string/select_job_type"/> <Spinner android:id="@+id/spinner_task" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:prompt="@string/select_task"/> <Spinner android:id="@+id/spinner_price" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:prompt="@string/view_price"/> </LinearLayout>
Now, let's wire up the spinners with Volley to load data and handle the联动. Here's the full activity code with comments explaining each part:
import android.os.Bundle import android.view.View import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.Spinner import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.android.volley.Request import com.android.volley.toolbox.StringRequest import com.android.volley.toolbox.Volley import org.json.JSONArray import org.json.JSONObject class MainActivity : AppCompatActivity() { private lateinit var jobTypeSpinner: Spinner private lateinit var taskSpinner: Spinner private lateinit var priceSpinner: Spinner private lateinit var requestQueue: Volley.RequestQueue // Store tasks and prices to sync them later private val taskList = mutableListOf<String>() private val priceList = mutableListOf<String>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Initialize all spinners jobTypeSpinner = findViewById(R.id.spinner_job_type) taskSpinner = findViewById(R.id.spinner_task) priceSpinner = findViewById(R.id.spinner_price) // Set up Volley's request queue (this handles all network calls) requestQueue = Volley.newRequestQueue(this) // Load the first spinner with job types from your server loadJobTypes() // Listen for selections on the job type spinner jobTypeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { // Get the selected job type's ID (use this to fetch matching tasks/prices) val selectedJob = parent?.getItemAtPosition(position) as JobType loadTasksAndPrices(selectedJob.id) } override fun onNothingSelected(parent: AdapterView<*>?) { // Clear the other spinners if no job is selected taskList.clear() priceList.clear() updateTaskAndPriceSpinners() } } // Optional: Sync task and price selections (so choosing a task auto-selects its price) taskSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { priceSpinner.setSelection(position) } override fun onNothingSelected(parent: AdapterView<*>?) {} } } private fun loadJobTypes() { // Replace this URL with your actual server endpoint for job types val jobTypeUrl = "https://your-server.com/api/get-job-types" val stringRequest = StringRequest( Request.Method.GET, jobTypeUrl, { response -> // Parse the JSON response into a list of JobType objects val jobTypes = mutableListOf<JobType>() val jsonArray = JSONArray(response) for (i in 0 until jsonArray.length()) { val jobObj = jsonArray.getJSONObject(i) val jobId = jobObj.getString("id") // Match your backend's JSON key val jobName = jobObj.getString("name") jobTypes.add(JobType(jobId, jobName)) } // Attach the list to the job type spinner val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, jobTypes) adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) jobTypeSpinner.adapter = adapter }, { error -> // Show an error message if the request fails Toast.makeText(this, "Failed to load job types: ${error.message}", Toast.LENGTH_SHORT).show() } ) // Add the request to Volley's queue to execute it requestQueue.add(stringRequest) } private fun loadTasksAndPrices(jobId: String) { // Replace this URL with your endpoint that takes a job ID and returns tasks/prices val taskPriceUrl = "https://your-server.com/api/get-tasks?jobId=$jobId" val stringRequest = StringRequest( Request.Method.GET, taskPriceUrl, { response -> // Clear old data before loading new taskList.clear() priceList.clear() val jsonArray = JSONArray(response) for (i in 0 until jsonArray.length()) { val taskPriceObj = jsonArray.getJSONObject(i) val taskName = taskPriceObj.getString("task_name") // Match your JSON key val price = taskPriceObj.getString("price") taskList.add(taskName) priceList.add(price) } // Update the task and price spinners with new data updateTaskAndPriceSpinners() }, { error -> Toast.makeText(this, "Failed to load tasks/prices: ${error.message}", Toast.LENGTH_SHORT).show() // Clear old data to avoid showing stale info taskList.clear() priceList.clear() updateTaskAndPriceSpinners() } ) requestQueue.add(stringRequest) } private fun updateTaskAndPriceSpinners() { // Update task spinner val taskAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, taskList) taskAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) taskSpinner.adapter = taskAdapter // Update price spinner val priceAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, priceList) priceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) priceSpinner.adapter = priceAdapter } }
- Replace Server URLs & JSON Keys: Make sure the URLs match your backend endpoints, and the JSON field names (like
"id","name","task_name") exactly match what your server returns. - Simplify JSON Parsing (Optional): If you don't want to manually parse JSON, you can use libraries like Gson or Moshi to convert JSON directly into your data classes—this saves time and reduces errors.
- Error Handling: The code includes basic error handling with Toasts, but you can expand this (e.g., showing a retry button) for better user experience.
Hope this helps you get your spinner联动 up and running smoothly!
内容的提问来源于stack exchange,提问作者amal

