使用Volley+JSON连接SQL Server到Android Studio遇连接错误及图片显示求助
Hey there! Let's break down and fix your two core issues: the connection error stopping your ListView from loading data, and displaying varbinary(MAX) images from SQL Server in your ListView.
1. Troubleshooting the "Error in connection" Issue
First, let's get your data loading working step by step:
Step 1: Verify Server & URL Reachability
- Double-check that your URL
http://myIP-Here/MSSQL/client.phpworks directly in your phone's browser. If it doesn't:- Replace
myIP-Herewith your computer's local network IP (e.g.,192.168.1.100) instead oflocalhostor127.0.0.1(your phone can't reach your computer's loopback address). - Ensure your computer and phone are on the same WiFi network.
- Confirm the PHP file path is correct (no typos in
/MSSQL/client.php).
- Replace
Step 2: Add Critical Network Permissions
Make sure your AndroidManifest.xml includes the internet permission (Volley can't send requests without this):
<uses-permission android:name="android.permission.INTERNET" />
For Android 9+, you also need to allow cleartext HTTP (if you're not using HTTPS):
<application ... android:usesCleartextTraffic="true"> ... </application>
Step 3: Fix Adapter Initialization Order
Your current code sets the adapter before adding data to rowItems—so the adapter never sees the new data. Here's the corrected subject() method:
public void subject(){ String url = "http://your-local-ip/MSSQL/client.php"; StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String response) { Log.d("Raw Response", response); try { JSONObject jsonObj = new JSONObject(response); peoples = jsonObj.getJSONArray("json"); mylistview = findViewById(R.id.list); // Clear old data first rowItems.clear(); // Populate data into rowItems for(int i=0;i<peoples.length();i++) { JSONObject c = peoples.getJSONObject(i); RowItem goodsItems = new RowItem(); goodsItems.setItem_id(c.getInt("item_id")); goodsItems.setItem_name(c.getString("item_name")); rowItems.add(goodsItems); } // Initialize adapter AFTER data is ready adapter = new CustomAdapter(MainActivity.this, rowItems); mylistview.setAdapter(adapter); mylistview.setOnItemClickListener(MainActivity.this); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(MainActivity.this, "JSON Parse Error: " + e.getMessage(), Toast.LENGTH_LONG).show(); } } }, new Response.ErrorListener() { public void onErrorResponse(VolleyError error) { // Get detailed error info instead of generic message String errorMsg = ""; if (error instanceof NetworkError) { errorMsg = "Check your WiFi/data connection"; } else if (error instanceof ServerError) { errorMsg = "Server error - check PHP logs"; // Print server's error response (if available) if (error.networkResponse != null) { String serverError = new String(error.networkResponse.data); Log.e("Server Error", serverError); } } else if (error instanceof TimeoutError) { errorMsg = "Request timed out - server might be slow"; } Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_LONG).show(); Log.e("Volley Error", errorMsg, error); } }){ @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<>(); return params; } }; RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this); requestQueue.add(stringRequest); }
Step 4: Validate PHP JSON Output
Ensure your client.php returns only valid JSON (no extra echo statements or HTML). A valid response should look like:
{"json":[{"item_id":1,"item_name":"Product 1"},{"item_id":2,"item_name":"Product 2"}]}
Use an online JSON validator to check the output.
2. Displaying varbinary(MAX) Images from SQL Server
There are two reliable ways to handle this—pick the one that fits your image size:
Option 1: Base64 String in JSON (For Small Images)
- Modify your PHP code to convert varbinary data to a Base64 string:
// Assuming your image column is named 'item_image' $item_image = base64_encode($row['item_image']); // Add this to your JSON output array - Update your RowItem class to hold the Base64 string:
public class RowItem { public int item_id; public String item_name; public String item_image_base64; // New field public RowItem() {} // Getters and setters public int getItem_id() { return item_id; } public void setItem_id(int item_id) { this.item_id = item_id; } public String getItem_name() { return item_name; } public void setItem_name(String item_name) { this.item_name = item_name; } public String getItem_image_base64() { return item_image_base64; } public void setItem_image_base64(String item_image_base64) { this.item_image_base64 = item_image_base64; } } - Parse the Base64 field in your
onResponsemethod:goodsItems.setItem_image_base64(c.getString("item_image")); - Load the image in CustomAdapter:
@Override public View getView(int position, View convertView, ViewGroup parent) { if (inflater == null) inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (convertView == null) convertView = inflater.inflate(R.layout.list_item, null); TextView item_id = convertView.findViewById(R.id.item_id); TextView item_name = convertView.findViewById(R.id.item_name); ImageView image = convertView.findViewById(R.id.imView); final RowItem m = rowItems.get(position); item_id.setText(String.valueOf(m.getItem_id())); item_name.setText(m.getItem_name()); // Load Base64 image if (m.getItem_image_base64() != null && !m.getItem_image_base64().isEmpty()) { byte[] decodedBytes = Base64.decode(m.getItem_image_base64(), Base64.DEFAULT); Bitmap bitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length); image.setImageBitmap(bitmap); } else { // Set a default placeholder image image.setImageResource(R.drawable.default_image); } return convertView; }
Option 2: Separate Image Endpoint (For Large Images)
This is better for bigger images since Base64 adds overhead.
- Create a PHP endpoint (e.g.,
get_image.php) to return the image stream:<?php $item_id = $_GET['item_id']; // Connect to SQL Server, query the item_image column for this item_id header("Content-Type: image/jpeg"); // Adjust based on your image type (png, etc.) echo $row['item_image']; ?> - Use Picasso (a popular image loading library) to load the image in your adapter:
- Add Picasso to your app-level
build.gradle:implementation 'com.squareup.picasso:picasso:2.71828' - Update your CustomAdapter's
getViewmethod:@Override public View getView(int position, View convertView, ViewGroup parent) { // ... existing code ... ImageView image = convertView.findViewById(R.id.imView); final RowItem m = rowItems.get(position); // Load image from the endpoint Picasso.with(activity) .load("http://your-local-ip/MSSQL/get_image.php?item_id=" + m.getItem_id()) .resize(300, 300) .placeholder(R.drawable.loading_image) .error(R.drawable.error_image) .into(image); return convertView; }
- Add Picasso to your app-level
内容的提问来源于stack exchange,提问作者Emily

