Android Studio中基于Volley实现返回JSONObject的方法及自定义观察者模式改造方案
Got it, let's walk through implementing a custom observer pattern for your weather app—no Android built-in Observer interface required. This setup will let MainActivity hold the latest weather JSONObject as the "subject", and your displayInfo activity act as an "observer" that gets notified when new data arrives, or can actively fetch the latest data whenever it needs.
Step 1: Define the Observer Interface
First, create a simple interface to standardize how observers react to weather data updates. All observers will implement this interface.
// Create this as a separate Java file or inside MainActivity public interface WeatherDataObserver { // Called when new weather data is available void onWeatherDataUpdated(JSONObject latestWeatherData); }
Step 2: Modify MainActivity to Act as the Subject
Update MainActivity to manage a list of observers, store the latest weather JSONObject, and handle notifications. Here's how to adjust your existing code:
public class MainActivity extends AppCompatActivity { // Your existing variables (searchBar, leftApiUrl, rightApiUrl, etc.) private List<WeatherDataObserver> observers = new ArrayList<>(); private JSONObject latestWeatherJson; // Holds the most recent weather data // Register an observer to receive updates public void registerObserver(WeatherDataObserver observer) { if (!observers.contains(observer)) { observers.add(observer); // Send existing data immediately if we already have it if (latestWeatherJson != null) { observer.onWeatherDataUpdated(latestWeatherJson); } } } // Remove an observer (critical to avoid memory leaks) public void unregisterObserver(WeatherDataObserver observer) { observers.remove(observer); } // Notify all registered observers of new data private void notifyObservers() { for (WeatherDataObserver observer : observers) { observer.onWeatherDataUpdated(latestWeatherJson); } } // Public method for observers to actively fetch the latest data public JSONObject getLatestWeatherData() { return latestWeatherJson; } // Update your existing getInfoMethod() to save data and notify observers public void getInfoMethod(){ String finalUrl =""; String cityName = searchBar.getText().toString().trim(); RequestQueue rQ = Volley.newRequestQueue(getApplicationContext()); finalUrl = leftApiUrl+cityName+rightApiUrl; StringRequest sR = new StringRequest(Request.Method.POST, finalUrl, new Response.Listener<String>() { @Override public void onResponse(String response) { try { JSONObject allJsonRes = new JSONObject(response); // Save the latest JSON data to our member variable latestWeatherJson = allJsonRes; // Notify all observers about the new data notifyObservers(); // You can remove the old Intent.putExtra code here—we're using the observer pattern now } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener(){ @Override public void onErrorResponse(VolleyError error) { Toast.makeText(getApplicationContext(),"Error,check network or spelling",Toast.LENGTH_SHORT).show(); } }); rQ.add(sR); } }
Step 3: Modify displayInfo to Act as the Observer
Make displayInfo implement the WeatherDataObserver interface, register itself with MainActivity, and update its UI when data changes.
public class displayInfo extends AppCompatActivity implements WeatherDataObserver { // Initialize your TextViews (match your layout IDs) private TextView cityNameTv; private TextView tempTv; private TextView mainDescTv; // ... add other TextViews you need @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_display_info_layout); // Initialize UI elements cityNameTv = findViewById(R.id.city_name_tv); tempTv = findViewById(R.id.temp_tv); mainDescTv = findViewById(R.id.main_desc_tv); // ... initialize other TextViews // Register this activity as an observer to MainActivity // Note: If you start displayInfo from MainActivity, you can get the reference via getParent() // For production apps, consider using a singleton Subject or ViewModel for safer communication MainActivity mainActivity = (MainActivity) getParent(); if (mainActivity != null) { mainActivity.registerObserver(this); // Optionally: Actively fetch the latest data right away if it exists JSONObject latestData = mainActivity.getLatestWeatherData(); if (latestData != null) { updateUI(latestData); } } } @Override public void onWeatherDataUpdated(JSONObject latestWeatherData) { // Update the UI with the new weather data updateUI(latestWeatherData); } private void updateUI(JSONObject weatherData) { try { // Parse data from the JSONObject (reuse your existing parsing logic) String cityName = weatherData.getString("name"); double temp = weatherData.getJSONObject("main").getDouble("temp"); String mainDesc = weatherData.getJSONArray("weather").getJSONObject(0).getString("main"); // ... parse all other fields you need // Update TextViews cityNameTv.setText(cityName); tempTv.setText(Math.round(temp) + "°C"); mainDescTv.setText(mainDesc); // ... update other UI elements } catch (JSONException e) { e.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); // Unregister the observer to prevent memory leaks MainActivity mainActivity = (MainActivity) getParent(); if (mainActivity != null) { mainActivity.unregisterObserver(this); } } }
Key Notes for Robustness
- Memory Leak Prevention: Always unregister observers in
onDestroy()—this ensures MainActivity doesn't hold references to destroyed activities. - Thread Safety: If you ever modify the observer list from a background thread, use a thread-safe list like
CopyOnWriteArrayListinstead ofArrayList. - Alternative Communication: For more complex app flows, consider using a singleton
WeatherDataSubjectclass or Android ViewModel to manage the observer list and data—this avoids relying ongetParent()which can be fragile.
内容的提问来源于stack exchange,提问作者MUCHUAN SU

