2016-04-02 25 views
1

Bir API'den veri alarak ListView'ü güncelleyen bir ArrayAdapter kullanıyorum. API çalışıyor ve bir AsyncTask kullanarak veri alıyorum.java.lang.NullPointerException: Boş bir nesne başvurusunda sanal yöntem 'void android.widget.ArrayAdapter.clear()' yöntemini çağırmayı denemek

OnPostExecute yöntemi, ArrayAdapter'ı temizlemeli ve buna yeni veriler eklemelidir.

Ama soruna neden olan kesin hat için 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); 
     } 
    } 
} 

kontrol Line 351 diyerek bazı hatalar karşı karşıyayım.

Bu bir sorun değil, ancak Android Geliştirmede yeniyim.

çizgisinde WeatherFragment.java olarak
+0

bazı repo kaynaklarını görmek/kontrol etmek için bize bağlantı vermek yerine ilgili kodu buraya gönderin ... –

+0

'PostConute'de' Adapter 'ayarlamayı deneyin. Bunu, 'Create Create on' dan 'Post Execute' 'a aktarın. –

+0

@ itsashis4u Post kod snippet'lerini repo'dan (bununla birlikte ikincil bir kaynak olarak kullanabilirsiniz).ArrayAdapter'ınızı nerede oluşturduğunuzu gösterin ve temizlemeye çalıştığınız yeri gösterin. Kod dökümleri ve "Neden bu işe yaramıyor?" iyi sorular değil. – TEK

cevap

2

Bu oldukça yaygın bir sorundur. Bunu düşünmenin bir yolu, bir AsyncTask başladıktan sonra, gerçekten ne zaman sona ereceğine dair çok fazla kontrole sahip olmamanız olabilir, çünkü bu, bir dizi faktöre, görev boyutuna, vb. Bağlı olarak değişir. AsyncTask'un kendisi mevcut olmayabilir.

Sizin durumunuza göre, mAdapternull olarak ayarlanıyor ve bu nedenle NullPointerException neden oluyor, aşağıdakilerden birini yapmanızı öneririm. OnPostExecute (..) içindeki

  • ,

  • ( view kendisi inaktif hale gelip gelmediğini bu wont'work) o null ise öncelikleTakvimlerim mAdapter yeniden başlatır UI iş parçacığı üzerinde bir etkinlik başlatmak
  • AsyncTask numaranıza bir geri bildirim işleyici işlevini iletin; AsyncTask döndüğünde parçanın başlatıldığından ve çalıştırıldığından emin olmak için işlev WeatherFragment olmalıdır; mAdapter yeniden sıfırlanırsa ve AsyncTask'dan alınan verilere göre uygun şekilde UI güncelleştirilirse yeniden başlatılır.

Maalesef, daha özel bir sorun göndermediyseniz, bunlar akla gelen yalnızca 2 öneridir. Google'da bu tasarım seçeneklerinin her biri için çok sayıda kaynak bulabilirsiniz. Her iki şekilde işe yarayacaksa haber ver.

+0

Teşekkürler. Ben Android Dev için yeni. Temelleri anlamak gerekiyor. – itsashis4u

+0

@ itsashis4u Bu herhangi bir şekilde yardımcı oldu mu? –

+0

Evet, sorun etkinlik yaşam döngüsü ile ilişkiliydi. – itsashis4u

1

bir 251

mAdapter.clear();

ilk deneme) (eğer

mAdapter = new ArrayAdapter<String>(result); 

böyle yenisini atamak ve mAdapter.clear kaldırabilir bu kodu başka

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

kullanarak IsEmpty kontrol etmek;

İlgili konular