2016-04-02 36 views
1

APIからデータを取得してListViewを更新するArrayAdapterがあります。 APIは正常に動作しており、AsyncTaskを使用してデータを取得しています。java.lang.NullPointerException:ヌルオブジェクト参照で仮想メソッド 'void android.widget.ArrayAdapter.clear()'を呼び出そうとしました

OnPostExecuteメソッドは、ArrayAdapterをクリアして新しいデータを追加する必要があります。

しかし、私は、問題を引き起こしている正確なラインのjava.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ArrayAdapter.clear()' on a null object reference

package com.example.sunshine; 

import android.content.Context; 
import android.net.Uri; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.text.format.Time; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.ArrayAdapter; 
import android.widget.EditText; 
import android.widget.ListView; 

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

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.net.HttpURLConnection; 
import java.net.MalformedURLException; 
import java.net.ProtocolException; 
import java.net.URL; 
import java.text.SimpleDateFormat; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 


/** 
* A simple {@link Fragment} subclass. 
* Activities that contain this fragment must implement the 
* {@link WeatherFragment.OnFragmentInteractionListener} interface 
* to handle interaction events. 
* Use the {@link WeatherFragment#newInstance} factory method to 
* create an instance of this fragment. 
*/ 
public class WeatherFragment extends Fragment { 
    // TODO: Rename parameter arguments, choose names that match 
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER 
    private static final String ARG_PARAM1 = "param1"; 
    private static final String ARG_PARAM2 = "param2"; 
    private ArrayAdapter<String> mAdapter; 
    // TODO: Rename and change types of parameters 
    private String mParam1; 
    private String mParam2; 
    public EditText locationCity; 

    private OnFragmentInteractionListener mListener; 

    public WeatherFragment() { 
     // Required empty public constructor 
    } 

    /** 
    * Use this factory method to create a new instance of 
    * this fragment using the provided parameters. 
    * 
    * @param param1 Parameter 1. 
    * @param param2 Parameter 2. 
    * @return A new instance of fragment WeatherFragment. 
    */ 
    // TODO: Rename and change types and number of parameters 
    public static WeatherFragment newInstance(String param1, String param2) { 
     WeatherFragment fragment = new WeatherFragment(); 
     Bundle args = new Bundle(); 
     args.putString(ARG_PARAM1, param1); 
     args.putString(ARG_PARAM2, param2); 
     fragment.setArguments(args); 
     return fragment; 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     if (getArguments() != null) { 
      mParam1 = getArguments().getString(ARG_PARAM1); 
      mParam2 = getArguments().getString(ARG_PARAM2); 
     } 

    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     // Inflate the layout for this fragment 
     View view = inflater.inflate(R.layout.fragment_weather, container, false); 


     String[] forecastArray = {"Mon 6/23 - Sunny - 31/17", 
       "Tue 6/24 - Foggy - 21/8", 
       "Wed 6/25 - Cloudy - 22/17", 
       "Thurs 6/26 - Rainy - 18/11", 
       "Fri 6/27 - Foggy - 21/10", 
       "Sat 6/28 - TRAPPED IN WEATHERSTATION - 23/18", 
       "Sun 6/29 - Sunny - 20/7"}; 
     List<String> weekForecast = new ArrayList<>(Arrays.asList(forecastArray)); 
     mAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, weekForecast); 
     mAdapter.notifyDataSetChanged(); 
     ListView listView = (ListView) view.findViewById(R.id.listView1); 
     Log.d("Log", "If listview is null "+listView); 
     listView.setAdapter(mAdapter); 

     return view; 

    } 


    @Override 
    public void onAttach(Context context) { 
     super.onAttach(context); 
     if (context instanceof OnFragmentInteractionListener) { 
      mListener = (OnFragmentInteractionListener) context; 
     } else { 
      throw new RuntimeException(context.toString() 
        + " must implement OnFragmentInteractionListener"); 
     } 
    } 

    @Override 
    public void onDetach() { 
     super.onDetach(); 
     mListener = null; 
    } 

    /** 
    * This interface must be implemented by activities that contain this 
    * fragment to allow an interaction in this fragment to be communicated 
    * to the activity and potentially other fragments contained in that 
    * activity. 
    * <p/> 
    * See the Android Training lesson <a href= 
    * "http://developer.android.com/training/basics/fragments/communicating.html" 
    * >Communicating with Other Fragments</a> for more information. 
    */ 
    public interface OnFragmentInteractionListener { 
     // TODO: Update argument type and name 
     void onFragmentInteraction(Uri uri); 
    } 

    public class FetchWeatherTask extends AsyncTask<String, Void, String[]> { 

     private final String LOG_TAG = FetchWeatherTask.class.getSimpleName(); 

     /* The date/time conversion code is going to be moved outside the asynctask later, 
* so for convenience we're breaking it out into its own method now. 
*/ 
     private String getReadableDateString(long time){ 
      // Because the API returns a unix timestamp (measured in seconds), 
      // it must be converted to milliseconds in order to be converted to valid date. 
      SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("EEE MMM dd"); 
      return shortenedDateFormat.format(time); 
     } 

     /** 
     * Prepare the weather high/lows for presentation. 
     */ 
     private String formatHighLows(double high, double low) { 
      // For presentation, assume the user doesn't care about tenths of a degree. 
      long roundedHigh = Math.round(high); 
      long roundedLow = Math.round(low); 

      return roundedHigh + "/" + roundedLow; 

     } 

     /** 
     * Take the String representing the complete forecast in JSON Format and 
     * pull out the data we need to construct the Strings needed for the wireframes. 
     * 
     * Fortunately parsing is easy: constructor takes the JSON string and converts it 
     * into an Object hierarchy for us. 
     */ 
     private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays) 
       throws JSONException { 

      // These are the names of the JSON objects that need to be extracted. 
      final String OWM_LIST = "list"; 
      final String OWM_WEATHER = "weather"; 
      final String OWM_TEMPERATURE = "temp"; 
      final String OWM_MAX = "max"; 
      final String OWM_MIN = "min"; 
      final String OWM_DESCRIPTION = "main"; 

      JSONObject forecastJson = new JSONObject(forecastJsonStr); 
      JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST); 

      // OWM returns daily forecasts based upon the local time of the city that is being 
      // asked for, which means that we need to know the GMT offset to translate this data 
      // properly. 

      // Since this data is also sent in-order and the first day is always the 
      // current day, we're going to take advantage of that to get a nice 
      // normalized UTC date for all of our weather. 

      Time dayTime = new Time(); 
      dayTime.setToNow(); 

      // we start at the day returned by local time. Otherwise this is a mess. 
      int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff); 

      // now we work exclusively in UTC 
      dayTime = new Time(); 

      String[] resultStrs = new String[numDays]; 
      for(int i = 0; i < weatherArray.length(); i++) { 
       // For now, using the format "Day, description, hi/low" 
       String day; 
       String description; 
       String highAndLow; 

       // Get the JSON object representing the day 
       JSONObject dayForecast = weatherArray.getJSONObject(i); 

       // The date/time is returned as a long. We need to convert that 
       // into something human-readable, since most people won't read "1400356800" as 
       // "this saturday". 
       long dateTime; 
       // Cheating to convert this to UTC time, which is what we want anyhow 
       dateTime = dayTime.setJulianDay(julianStartDay+i); 
       day = getReadableDateString(dateTime); 

       // description is in a child array called "weather", which is 1 element long. 
       JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0); 
       description = weatherObject.getString(OWM_DESCRIPTION); 

       // Temperatures are in a child object called "temp". Try not to name variables 
       // "temp" when working with temperature. It confuses everybody. 
       JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE); 
       double high = temperatureObject.getDouble(OWM_MAX); 
       double low = temperatureObject.getDouble(OWM_MIN); 

       highAndLow = formatHighLows(high, low); 
       resultStrs[i] = day + " - " + description + " - " + highAndLow; 
      } 

      for (String s : resultStrs) { 
       Log.v(LOG_TAG, "Forecast entry: " + s); 
      } 
      return resultStrs; 

     } 

     @Override 
     protected String[] doInBackground(String... params) { 

      if(params.length == 0){ 
       return null; 
      } 

      HttpURLConnection urlConnection = null; 
      BufferedReader reader = null; 
      String format = "json"; 
      String units = "metric"; 
      int numDays = 7; 
      String forecastJSONStr = null; 

      try { 
       final String BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?"; 
       final String QUERY_PARAM = "q"; 
       final String FORMAT_PARAM = "mode"; 
       final String UNITS_PARAM = "units"; 
       final String COUNT_PARAM = "cnt"; 
       final String APPID_PARAM = "APPID"; 


       Uri builtUri = Uri.parse(BASE_URL).buildUpon() 
         .appendQueryParameter(QUERY_PARAM, params[0]) 
         .appendQueryParameter(FORMAT_PARAM, format) 
         .appendQueryParameter(UNITS_PARAM, units) 
         .appendQueryParameter(COUNT_PARAM, Integer.toString(numDays)) 
         .appendQueryParameter(APPID_PARAM, BuildConfig.OWMAPIKey) 
         .build(); 


       URL url = new URL(builtUri.toString()); 
       Log.v(LOG_TAG, "Built Uri"+ builtUri.toString()); 

       urlConnection = (HttpURLConnection) url.openConnection(); 
       urlConnection.setRequestMethod("GET"); 
       urlConnection.connect(); 

       InputStream inputStream = urlConnection.getInputStream(); 
       StringBuilder buffer = new StringBuilder(); 

       if(inputStream == null){ 
        forecastJSONStr = null; 
       } 
       if(inputStream != null){ 
        reader = new BufferedReader(new InputStreamReader(inputStream)); 
       } 

       String line; 
       if(reader != null){ 
        while((line = reader.readLine()) != null){ 
         buffer.append(line).append('\n'); 
        } 
       } 

       if(buffer.length() == 0){ 
        forecastJSONStr = null; 
       } 

       forecastJSONStr = buffer.toString(); 
       Log.e(LOG_TAG, "Forecast String " + forecastJSONStr); 
      } catch (ProtocolException | MalformedURLException e) { 
       e.printStackTrace(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
       Log.e(LOG_TAG, "onCreateView: Error", e); 
       forecastJSONStr = null; 
      }finally { 
       if(urlConnection != null){ 
        urlConnection.disconnect(); 
       } 
       if(reader != null){ 
        try { 
         reader.close(); 
        } catch (final IOException e) { 
         Log.e(LOG_TAG, "Error closing stream ", e); 
        } 
       } 
      } 
      try { 
       if(forecastJSONStr != null){ 
        Log.v(LOG_TAG, "doInBackground: "+forecastJSONStr); 
        String[] results= getWeatherDataFromJson(forecastJSONStr, numDays); 
        Log.v(LOG_TAG, "doInBackground: Check result" +Arrays.toString(results)); 
        return results; 
//     return getWeatherDataFromJson(forecastJSONStr, numDays); 
       } 
       else{ 
        Log.e(LOG_TAG, "Check your internet!"); 
       } 
      }catch (JSONException e){ 
       Log.e(LOG_TAG, e.getMessage(), e); 
       e.printStackTrace(); 
      } 
      return null; 
     } 

     @Override 
     protected void onPostExecute(String[] result) { 
      Log.v(LOG_TAG, "onPostExecute: Check result object" + Arrays.toString(result)); 
      Log.i(LOG_TAG, "onPostExecute: "+mAdapter); 
      mAdapter.clear(); 
      mAdapter.addAll(result); 
//   if(result != null){ 
////    for(String dayForecastStr : result) { 
////     mAdapter.add(dayForecastStr); 
////    } 
// 
//   } 
//   super.onPostExecute(result); 
     } 
    } 
} 

チェックLine 351を言っていくつかのエラーに直面しています。

迷惑メールに関する質問があれば謝罪しますが、Android開発の初心者です。

ラインでWeatherFragment.javaで
+0

私たちをリンクしていくつかのレポソースを確認するのではなく、関連するコードを投稿してください... –

+0

'on Post''メソッドに' Adapter'を設定してみてください。 'On Create View'から' Post Execute'に転送します。 –

+0

@ itsashis4uリポジトリからコードスニペットを投稿します(セカンダリソースとして使用することもできます)。'ArrayAdapter'をインスタンス化する場所を表示し、それをクリアしようとする場所を表示します。コードダンプと "なぜこれは機能しないのですか?"良い質問ではありません。 – TEK

答えて

2

これは非常に一般的な問題です。これについて考える方法の1つは、AsyncTaskが開始された後で、終了するタイミングを実際にはあまり制御することができないことです。これは、さまざまな要因、タスクのサイズなどに依存するためです。 AsyncTask自体が利用できない場合があります。

mAdapternullに設定されているため、NullPointerExceptionになっているので、次のいずれかをお勧めします。 onPostExecute(..)内部

  • 、それは(view自体が非アクティブになった場合、このwont'work)null

  • である場合には、第1あなたの mAdapterを再初期化することをUIスレッド上での活動を開始
  • AsyncTaskにコールバックハンドラ関数を渡します。 AsyncTaskが返されたときにフラグメントが初期化されて実行されていることを確認するには、関数はWeatherFragmentになければなりません。 mAdapterがnullの場合は再び再初期化し、AsyncTaskから受信したデータに基づいてUIを更新します。

残念ながら、あなたはより具体的な問題を投稿していないことを考えると、これらは、頭に浮かぶ唯一の2つの提案です。これらのデザインの選択肢ごとに、Googleで多数のリソースを見つけることができます。いずれかの方法が有効かどうかを教えてください。

+0

ありがとうございます。私はAndroid Devの新機能です。基本を理解する必要があります。 – itsashis4u

+0

@ itsashis4u何とか助けてくれましたか? –

+0

はい、この問題はアクティビティのライフサイクルに関連していました。 – itsashis4u

1

ない251

mAdapter.clear()。 (あなたが

mAdapter = new ArrayAdapter<String>(result); 

このような新しいものを割り当て、mAdapter.clearを削除することができ、このコードに

if(mAdapter.getCount()!=0 && mAdapter!=null){ 
    mAdapter.clear(); 
} 

を使用してのisEmptyをチェックする

最初の試み)。

関連する問題

 関連する問題