Volley+JSON操作WAMP MySQL:列表行ID传参及报错解决
Hey Saranya, let's break down your problems one by one and get this sorted out—you’ve spent enough time stuck on these!
1. Fixing "No adapter attached; skipping layout"
This error happens because your RecyclerView tries to render before an adapter is attached. Right now, you only set the adapter after Volley finishes fetching data, which can take time. Here’s how to fix it:
Update your initialization flow:
Initialize your RecyclerView, layout manager, empty adapter, and product list early (e.g., in
onCreate):@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_activity_layout); recyclerView = findViewById(R.id.your_recycler_view_id); recyclerView.setLayoutManager(new LinearLayoutManager(this)); // Initialize empty list and adapter first productList = new ArrayList<>(); myadapter = new ProductAdapter(this, productList); recyclerView.setAdapter(myadapter); // Now trigger your Volley request fetchProducts(); }In your Volley
onResponsemethod, replace thesetuprecyclerviewcall with a notify to update the existing adapter:try { JSONArray array = new JSONArray(response); for (int i = 0; i < array.length(); i++) { JSONObject product = array.getJSONObject(i); Product product1=new Product(); product1.setName(product.getString("name")); product1.setDescription(product.getString("description")); productList.add(product1); } // Notify adapter that data has changed myadapter.notifyDataSetChanged(); } catch (JSONException e) { e.printStackTrace(); }
2. Fixing "org.json.JSONException: Value Connected of type java.lang.String cannot be converted to JSONArray"
This means your PHP script is returning the string "Connected" instead of a valid JSON array. Let’s fix the PHP code:
Step 1: Correct your SQL query
Your original query has syntax errors (typos in table names and incorrect JOIN syntax). Use this instead:
$stmt = $conn->prepare("SELECT domainname.id, domainname.name, domaindescription.description FROM domainname INNER JOIN domaindescription ON domainname.id = domaindescription.id_fk");
(Note: I added domainname.id here—we’ll need it later for passing to the next Activity)
Step 2: Ensure PHP outputs only valid JSON
Remove any extra echo "Connected"; statements, and properly format your result as JSON:
<?php $servername = "localhost"; $username = "your_db_username"; $password = "your_db_password"; $dbname = "your_db_name"; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die(json_encode(["error" => "Connection failed: " . $conn->connect_error])); } $stmt = $conn->prepare("SELECT domainname.id, domainname.name, domaindescription.description FROM domainname INNER JOIN domaindescription ON domainname.id = domaindescription.id_fk"); $stmt->execute(); $result = $stmt->get_result(); $products = []; while($row = $result->fetch_assoc()) { $products[] = $row; } echo json_encode($products); $stmt->close(); $conn->close(); ?>
3. Passing MySQL Row ID to Another Activity & Displaying Details
Here’s a step-by-step implementation:
Step 1: Update your Product class to include the ID
Add an id field with getters/setters:
public class Product { private int id; private String name; private String description; // Constructor public Product() {} // Getters & Setters public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
Step 2: Parse the ID in your Volley response
Update the onResponse block to extract and set the ID:
JSONObject product = array.getJSONObject(i); Product product1=new Product(); product1.setId(product.getInt("id")); // Add this line product1.setName(product.getString("name")); product1.setDescription(product.getString("description")); productList.add(product1);
Step 3: Add click listener to your RecyclerView Adapter
Modify your ProductAdapter to handle item clicks and pass the ID to the next Activity:
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductViewHolder> { private Context context; private List<Product> productList; public ProductAdapter(Context context, List<Product> productList) { this.context = context; this.productList = productList; } @NonNull @Override public ProductViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.your_item_layout, parent, false); return new ProductViewHolder(view); } @Override public void onBindViewHolder(@NonNull ProductViewHolder holder, int position) { Product product = productList.get(position); holder.tvName.setText(product.getName()); holder.tvDesc.setText(product.getDescription()); // Handle item click holder.itemView.setOnClickListener(v -> { Intent intent = new Intent(context, ProductDetailActivity.class); intent.putExtra("PRODUCT_ID", product.getId()); context.startActivity(intent); }); } @Override public int getItemCount() { return productList.size(); } public static class ProductViewHolder extends RecyclerView.ViewHolder { TextView tvName, tvDesc; public ProductViewHolder(@NonNull View itemView) { super(itemView); tvName = itemView.findViewById(R.id.tv_item_name); tvDesc = itemView.findViewById(R.id.tv_item_description); } } }
Step 4: Create ProductDetailActivity to fetch and display details
This Activity will receive the ID and fetch the corresponding data from your server:
public class ProductDetailActivity extends AppCompatActivity { private TextView tvDetailName, tvDetailDesc; private static final String URL_DETAIL = "http://your_wamp_ip/get_product_detail.php"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_product_detail); tvDetailName = findViewById(R.id.tv_detail_name); tvDetailDesc = findViewById(R.id.tv_detail_description); // Get the passed product ID int productId = getIntent().getIntExtra("PRODUCT_ID", -1); if (productId != -1) { fetchProductDetails(productId); } } private void fetchProductDetails(int productId) { StringRequest stringRequest = new StringRequest(Request.Method.GET, URL_DETAIL + "?id=" + productId, response -> { try { JSONObject product = new JSONObject(response); tvDetailName.setText(product.getString("name")); tvDetailDesc.setText(product.getString("description")); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(this, "Failed to load details", Toast.LENGTH_SHORT).show(); } }, error -> Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show()); Volley.newRequestQueue(this).add(stringRequest); } }
Step 5: Create the PHP script for detail data (get_product_detail.php)
<?php $servername = "localhost"; $username = "your_db_username"; $password = "your_db_password"; $dbname = "your_db_name"; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die(json_encode(["error" => "Connection failed: " . $conn->connect_error])); } $productId = $_GET['id']; $stmt = $conn->prepare("SELECT domainname.name, domaindescription.description FROM domainname INNER JOIN domaindescription ON domainname.id = domaindescription.id_fk WHERE domainname.id = ?"); $stmt->bind_param("i", $productId); $stmt->execute(); $result = $stmt->get_result(); if ($result->num_rows > 0) { echo json_encode($result->fetch_assoc()); } else { echo json_encode(["error" => "Product not found"]); } $stmt->close(); $conn->close(); ?>
Quick Reminders:
- Make sure your Android device and WAMP server are on the same local network
- Add internet permission to your
AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" /> - Double-check your database credentials in the PHP scripts
内容的提问来源于stack exchange,提问作者Saranya

