Android数据变更后GridView无法刷新的问题求助
问题描述
首次通过API获取数据后,MainActivity的GridView能正常展示并更新,但点击GridView项触发设备状态变更后,GridView无法刷新展示更新后的数据,尽管调用了首次加载时的相同回调方法。
APIManager.java
public class APIManager { DeviceCallback deviceCallback; private static final String TAG = "APIManager"; private static final String API_URL = "https://base-url"; private static final String AUTH_TOKEN = SplashScreen.getTOKEN(); private static List<Device> deviceArray = null; public void setDeviceCallback(DeviceCallback deviceCallback) { this.deviceCallback = deviceCallback; } void toggleDeviceState(Context context, String deviceID) { String URL = "https://baseurl/" + deviceID; RequestQueue requestQueue = Volley.newRequestQueue(context); JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, URL, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { parseToggleStateResponse(response); } catch (JSONException e) { Log.e(TAG, "JSON parsing error: " + e.getMessage()); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e(TAG, "API error: " + error.getMessage()); } }) { @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> headers = new HashMap<>(); headers.put("Authorization", "jwt " + AUTH_TOKEN); return headers; } }; requestQueue.add(jsonObjectRequest); } void fetchInitialData(Context context) { RequestQueue requestQueue = Volley.newRequestQueue(context); JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, API_URL, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { parseResponseData(response); JSONArray ownDevices = response.getJSONArray("owndevices"); } catch (JSONException e) { Log.e(TAG, "JSON parsing error: " + e.getMessage()); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e(TAG, "API error: " + error.getMessage()); } }) { @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> headers = new HashMap<>(); headers.put("Authorization", "Jwt " + AUTH_TOKEN); return headers; } }; requestQueue.add(jsonObjectRequest); } ToggleResponse parseToggleStateResponse(JSONObject response) throws JSONException { Gson gson = new Gson(); JSONObject device = response.getJSONObject("data"); Device deviceData = gson.fromJson(device.toString(), Device.class); Log.w("API-MANAGER", "125 : Response = " + deviceData.getId()); for (int i = 0; i < deviceArray.toArray().length; i++) { String deviceID = deviceArray.get(i).getId(); if (deviceID == deviceData.getId()) { Log.w("API-MANAGER", "DEVICE FOUND : " + deviceArray.get(i).getGivenName()); deviceArray.get(i).setState(deviceData.isState()); deviceCallback.deviceCallbackFunction(deviceArray); } } ToggleResponse responseData = new ToggleResponse(deviceData, message); return responseData; } DeviceResponse parseResponseData(JSONObject response) throws JSONException { Gson gson = new Gson(); JSONArray ownDevicesArray = response.getJSONArray("owndevices"); Device ownDevices[] = gson.fromJson(String.valueOf(ownDevicesArray), Device[].class); DeviceResponse responseData = new DeviceResponse(ownDevices); List<Device> ownDevice = new ArrayList<>(); List<Device> delDevice = new ArrayList<>(); for (int i = 0; i < ownDevicesArray.length(); i++) { JSONObject deviceObject = ownDevicesArray.getJSONObject(i); Device device = new Device(); Log.w("API-MANAGER", "153" + deviceObject.getString("_id")); device.set_id(deviceObject.getString("_id")); device.setName(deviceObject.getString("name")); device.setGivenName(deviceObject.getString("givenName")); device.setState(deviceObject.getBoolean("state")); device.setAdmin(deviceObject.getString("admin")); device.setDelegate(getStringListFromJSONArray(deviceObject.getJSONArray("delegate"))); device.setSchedulerFlag(deviceObject.getBoolean("schedulerFlag")); device.setTopic(deviceObject.getString("topic")); device.setMultiState(deviceObject.optString("multiState")); ownDevice.add(device); } deviceArray = ownDevice; deviceCallback.deviceCallbackFunction(ownDevice); responseData.setOwndevices(ownDevice); return responseData; } private List<String> getStringListFromJSONArray(JSONArray jsonArray) throws JSONException { List<String> list = new ArrayList<>(); for (int i = 0; i < jsonArray.length(); i++) { list.add(jsonArray.getString(i)); } return list; } public interface DeviceCallback { void deviceCallbackFunction(List<Device> deviceData); } }
GridAdapter.java
public class GridAdapter extends BaseAdapter{ Context context; private final List<Device> deviceData; LayoutInflater layoutInflater; APIManager apiManager = new APIManager(); public GridAdapter(Context context, List<Device> deviceData) { this.context = context; this.deviceData = deviceData; } @Override public int getCount() { return deviceData.toArray().length; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(final int position, View convertView, ViewGroup parent) { layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); Holder holder = new Holder(); View rowView; rowView = layoutInflater.inflate(R.layout.grid_item_layout, null); holder.GivenName = (TextView) rowView.findViewById(R.id.GivenName); holder.image= (ImageView) rowView.findViewById(R.id.image); holder.image.setImageResource(deviceData.get(position).isState()? R.drawable.switch_on : R.drawable.switch_off); holder.GivenName.setText(deviceData.get(position).getGivenName()); rowView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { apiManager.toggleDeviceState(context.getApplicationContext(), deviceData.get(position).getId()); Toast.makeText(context, "You Clicked "+deviceData.get(position).getId(), Toast.LENGTH_LONG).show(); notifyDataSetChanged(); } }); return rowView; } public class Holder { TextView Name; TextView GivenName; TextView State; TextView MultiState; TextView ConnectFlag; ImageView image; } }
MainActivity.java
import io.socket.client.Socket; public class MainActivity extends AppCompatActivity implements APIManager.DeviceCallback { public static GridView gridView; private Boolean hasConnection = false; String token = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE); token = sharedPreferences.getString("token", null); APIManager apiManager = new APIManager(); SocketClass socketClass = new SocketClass(); apiManager.setDeviceCallback(this); apiManager.fetchData(getApplicationContext()); getSupportActionBar().setTitle("Home"); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); gridView = (GridView) findViewById(R.id.gridview); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_menu, menu); return true; } @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { Log.w("API-MANAGER", "Item : " + item.toString()); return super.onOptionsItemSelected(item); } @Override public void deviceCallbackFunction(List<Device> deviceData) { GridAdapter gridAdapter = new GridAdapter(this, deviceData); Log.w("API-MANAGER", "49" + deviceData.get(0).getGivenName()); gridView.setAdapter(gridAdapter); } }
问题原因与修复方案
1. GridAdapter使用未绑定回调的新APIManager实例
GridAdapter中apiManager = new APIManager()是全新实例,未设置DeviceCallback,导致调用toggleDeviceState后,API响应无法通知到MainActivity。
修复:
- 修改GridAdapter构造方法,传入已绑定回调的APIManager实例:
private APIManager apiManager; public GridAdapter(Context context, List<Device> deviceData, APIManager apiManager) { this.context = context; this.deviceData = deviceData; this.apiManager = apiManager; }
- MainActivity创建Adapter时传入实例:
gridAdapter = new GridAdapter(this, deviceData, apiManager);
2. 字符串比较误用==
parseToggleStateResponse中用deviceID == deviceData.getId()比较字符串,==判断的是对象引用而非内容,会导致设备匹配失败,无法更新状态。
修复:
改用equals()比较内容:
if (deviceID.equals(deviceData.getId())) { // 设备状态更新逻辑 }
3. MainActivity每次回调都新建Adapter
原代码每次回调都创建新GridAdapter,既浪费资源,又可能导致数据源不一致。应复用Adapter实例,更新数据源后触发刷新。
修复:
- MainActivity中保存Adapter实例:
private GridAdapter gridAdapter;
- 回调中复用实例:
@Override public void deviceCallbackFunction(List<Device> deviceData) { if (gridAdapter == null) { gridAdapter = new GridAdapter(this, deviceData, apiManager); gridView.setAdapter(gridAdapter); } else { gridAdapter.updateData(deviceData); } }
- GridAdapter添加数据更新方法:
public void updateData(List<Device> newDeviceData) { this.deviceData.clear(); this.deviceData.addAll(newDeviceData); notifyDataSetChanged(); }
4. MainActivity调用不存在的方法
APIManager中只有fetchInitialData方法,原代码写的apiManager.fetchData是笔误,会导致编译错误。
修复:
改为apiManager.fetchInitialData(getApplicationContext())
5. GridAdapter未复用convertView(性能优化)
原代码每次getView都重新inflate布局,影响滚动性能,建议修复:
@Override public View getView(final int position, View convertView, ViewGroup parent) { Holder holder; if (convertView == null) { layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = layoutInflater.inflate(R.layout.grid_item_layout, parent, false); holder = new Holder(); holder.GivenName = convertView.findViewById(R.id.GivenName); holder.image = convertView.findViewById(R.id.image); convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); } // 设置数据 holder.image.setImageResource(deviceData.get(position).isState()? R.drawable.switch_on : R.drawable.switch_off); holder.GivenName.setText(deviceData.get(position).getGivenName()); convertView.setOnClickListener(v -> { apiManager.toggleDeviceState(context.getApplicationContext(), deviceData.get(position).getId()); Toast.makeText(context, "You Clicked "+deviceData.get(position).getId(), Toast.LENGTH_LONG).show(); }); return convertView; }
内容的提问来源于stack exchange,提问作者Amorphous
相关产品推荐
相关产品推荐

