在输入框(EditText)中输入文本时出现空指针异常(NullPointerException)。

huangapple 未分类评论46阅读模式
英文:

Getting NullPointerException when inputting text in an EditText

问题

在使用Android应用程序搜索城市时出现了错误。在我输入城市、州和国家(例如:纽约,纽约,美国)后,按下搜索按钮,应用程序崩溃并显示了一个NullPointerException。

MainActivity.java

// ... (之前的代码)

// create Weather objects from JSONObject containing the forecast
private void convertJSONtoArrayList(JSONObject forecast) {
    weatherList.clear(); // clear old weather data

    try {
        // get forecast's "list" JSONArray
        JSONArray list = forecast.getJSONArray("list");

        // convert each element of list to a Weather object
        for (int i = 0; i < list.length(); ++i) {
            JSONObject day = list.getJSONObject(i); // get one day's data
            // ... (继续之后的代码)
        }
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

// ... (之后的代码)

这是来自堆栈跟踪的错误消息:

java.lang.NullPointerException: Attempt to invoke virtual method 'org.json.JSONArray org.json.JSONObject.getJSONArray(java.lang.String)' on a null object reference                         

at com.xxxx.weatherviewer.MainActivity.convertJSONtoArrayList(MainActivity.java:171)
at com.xxxx.weatherviewer.MainActivity.access$300(MainActivity.java:30)
at com.xxxx.weatherviewer.MainActivity$GetWeatherTask.onPostExecute(MainActivity.java:157)
at com.xxxx.weatherviewer.MainActivity$GetWeatherTask.onPostExecute(MainActivity.java:106)
at android.os.AsyncTask.finish(AsyncTask.java:755)
at android.os.AsyncTask.access$900(AsyncTask.java:192)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:772)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

我认为下面这行代码可能存在问题:

JSONArray list = forecast.getJSONArray("list");

然而,我不确定如何解决问题... 有人能帮助我吗?

英文:

An error occurs when searching for a city using the Android application. After I type a city, state, country (for example: New York, New York, US) and press the search button, the app crashes and gives me a NullPointerException.

MainActivity.java

package com.xxxx.weatherviewer;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ListView;

import androidx.coordinatorlayout.widget.CoordinatorLayout;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    // List of Weather objects representing the forecast
    private List&lt;Weather&gt; weatherList = new ArrayList&lt;&gt;();

    // ArrayAdapter for binding Weather objects to a ListView
    private WeatherArrayAdapter weatherArrayAdapter;
    private ListView weatherListView; // displays weather info

    // configure Toolbar, ListView and FAB
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // autogenerated code to inflate layout and configure Toolbar
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // create ArrayAdapter to bind weatherList to the weatherListView
        weatherListView = findViewById(R.id.weatherListView);
        weatherArrayAdapter = new WeatherArrayAdapter(this, weatherList);
        weatherListView.setAdapter(weatherArrayAdapter);

        // configure FAB to hide keyboard and initiate web service request
        FloatingActionButton fab =
                findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // get text from locationEditText and create web service URL
                EditText locationEditText =
                        findViewById(R.id.locationEditText);
                URL url = createURL(locationEditText.getText().toString());

                // hide keyboard and initiate a GetWeatherTask to download
                // weather data from OpenWeatherMap.org in a separate thread
                if (url != null) {
                    dismissKeyboard(locationEditText);
                    GetWeatherTask getLocalWeatherTask = new GetWeatherTask();
                    getLocalWeatherTask.execute(url);
                }
                else {
                    Snackbar.make(findViewById(R.id.coordinatorLayout),
                            R.string.invalid_url, Snackbar.LENGTH_LONG).show();
                }
            }
        });
    }

    // programmatically dismiss keyboard when user touches FAB
    private void dismissKeyboard(View view) {
        InputMethodManager imm = (InputMethodManager) getSystemService(
                Context.INPUT_METHOD_SERVICE);
        assert imm != null;
        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }

    // create openweathermap.org web service URL using city
    private URL createURL(String city) {
        String apiKey = getString(R.string.api_key);
        String baseUrl = getString(R.string.web_service_url);

        try {
            // create URL for specified city and imperial units (Fahrenheit)
            String urlString = baseUrl + URLEncoder.encode(city, &quot;UTF-8&quot;) +
                    &quot;&amp;units=imperial&amp;cnt=16&amp;APPID=&quot; + apiKey;
            return new URL(urlString);
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        return null; // URL was malformed
    }

    // makes the REST web service call to get weather data and
    // saves the data to a local HTML file
    private class GetWeatherTask extends AsyncTask&lt;URL, Void, JSONObject&gt; {

        @Override
        protected JSONObject doInBackground(URL... params) {
            HttpURLConnection connection = null;

            try {
                connection = (HttpURLConnection) params[0].openConnection();
                int response = connection.getResponseCode();

                if (response == HttpURLConnection.HTTP_OK) {
                    StringBuilder builder = new StringBuilder();

                    try (BufferedReader reader = new BufferedReader(
                            new InputStreamReader(connection.getInputStream()))) {

                        String line;

                        while ((line = reader.readLine()) != null) {
                            builder.append(line);
                        }
                    }
                    catch (IOException e) {
                        Snackbar.make(findViewById(R.id.coordinatorLayout),
                                R.string.read_error, Snackbar.LENGTH_LONG).show();
                        e.printStackTrace();
                    }

                    return new JSONObject(builder.toString());
                }
                else {
                    Snackbar.make(findViewById(R.id.coordinatorLayout),
                            R.string.connect_error, Snackbar.LENGTH_LONG).show();
                }
            }
            catch (Exception e) {
                Snackbar.make(findViewById(R.id.coordinatorLayout),
                        R.string.connect_error, Snackbar.LENGTH_LONG).show();
                e.printStackTrace();
            }
            finally {
                assert connection != null;
                connection.disconnect(); // close the HttpURLConnection
            }

            return null;
        }

        // process JSON response and update ListView
        @Override
        protected void onPostExecute(JSONObject weather) {
            convertJSONtoArrayList(weather); // repopulate weatherList
            weatherArrayAdapter.notifyDataSetChanged(); // rebind to ListView
            weatherListView.smoothScrollToPosition(0); // scroll to top
        }
    }

    // create Weather objects from JSONObject containing the forecast
    private void convertJSONtoArrayList(JSONObject forecast) {
        weatherList.clear(); // clear old weather data

        try {
            // get forecast&#39;s &quot;list&quot; JSONArray

            JSONArray list =   forecast.getJSONArray(&quot;list&quot;);

            // convert each element of list to a Weather object
            for (int i = 0; i &lt; list.length(); ++i) {
                JSONObject day = list.getJSONObject(i); // get one day&#39;s data

                // get the day&#39;s temperatures (&quot;temp&quot;) JSONObject
                JSONObject temperatures = day.getJSONObject(&quot;temp&quot;);

                // get day&#39;s &quot;weather&quot; JSONObject for the description and icon
                JSONObject weather =
                        day.getJSONArray(&quot;weather&quot;).getJSONObject(0);

                // add new Weather object to weatherList
                weatherList.add(new Weather(
                        day.getLong(&quot;dt&quot;), // date/time timestamp
                        temperatures.getDouble(&quot;min&quot;), // minimum temperature
                        temperatures.getDouble(&quot;max&quot;), // maximum temperature
                        day.getDouble(&quot;humidity&quot;), // percent humidity
                        weather.getString(&quot;description&quot;), // weather conditions
                        weather.getString(&quot;icon&quot;))); // icon name
            }
        }
        catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

This is the error message from the stacktrace:

java.lang.NullPointerException: Attempt to invoke virtual method &#39;org.json.JSONArray org.json.JSONObject.getJSONArray(java.lang.String)&#39; on a null object reference                         

at com.xxxx.weatherviewer.MainActivity.convertJSONtoArrayList(MainActivity.java:171)
at com.xxxx.weatherviewer.MainActivity.access$300(MainActivity.java:30)
at com.xxxx.weatherviewer.MainActivity$GetWeatherTask.onPostExecute(MainActivity.java:157)
at com.xxxx.weatherviewer.MainActivity$GetWeatherTask.onPostExecute(MainActivity.java:106)
at android.os.AsyncTask.finish(AsyncTask.java:755)
at android.os.AsyncTask.access$900(AsyncTask.java:192)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:772)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

I believe there might be an issue with the line listed below:

JSONArray list =   forecast.getJSONArray(&quot;list&quot;);

However, I am unsure of how to start....can someone please help me?

答案1

得分: 0

一个简单的修复方法是将您的 catch 块从:

catch (JSONException e) {
   e.printStackTrace();
}

改为:

catch (Exception e) {
   e.printStackTrace();
}

这会捕获您的 NPE,但请注意,如果针对此处有一个 API,"list" 值可能是空的,或者在该情况下该值为 null,您可以在对 JSONArray list 变量执行操作之前始终进行检查。因此,例如在执行以下操作之前:

JSONObject day = list.getJSONObject(i);

您可以将其包装在以下内容中:

if(forecast.has(&quot;list&quot;)) {
   JSONObject day = list.getJSONObject(i);
   // 对 day 等的操作也是一样的...
}

这可以确保在处理对象之前首先检查该对象是否存在,以避免 NPE。

英文:

A simple fix could be to turn your catch block from:

catch (JSONException e) {
   e.printStackTrace();
}

into:

catch (Exception e) {
   e.printStackTrace();
}

This catches your NPE, but do note that, if you have an API for this the "list" value could be empty or having a null value in that case you can always have a checker before doing the operation on JSONArray list variable. So for example before doing this:

JSONObject day = list.getJSONObject(i);

you can surround it with:

if(forecast.has(&quot;list&quot;)) {
   JSONObject day = list.getJSONObject(i);
   // Same goes for day etc...
}

This ensures that it should check if the object exists in the first place before processing it to avoid NPE.

huangapple
  • 本文由 发表于 2020年4月7日 12:09:06
  • 转载请务必保留本文链接:https://java.coder-hub.com/61072692.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定