Android阳光应用(udacity)空白列表视图

时间:2015-10-13 19:30:39

标签: android listview

我已成功实施了针对天气预报的android阳光应用程序。它工作正常。

我通过更新程序应用程序进行了一些更新,我当前的版本是:6.7.1.0(KHJMICH),操作系统是4.4.4KTU84P,我的手机是redmii 2.

现在问题来了,我完全不知道这是怎么发生的。每当我运行我的应用程序时,都会出现一个空白列表视图。

所以基本上我使用发送到openweathermap的http查询获取json格式的天气预报,然后填充listview。

我的源代码没有修改,它是相同的。这让我最困惑的是

以下是填充列表视图的代码。

package com.example.hp.weather_app;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.text.format.Time;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

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.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;

/**
 * Created by hp on 20-06-2015.
 */

public  class MainActivityFragment extends Fragment {
    static ArrayAdapter<String> weather_adapter;
    public MainActivityFragment() {
    }
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootview = inflater.inflate(R.layout.fragment_main, container, false);
        ArrayList<String> x = new ArrayList<String>();
        weather_adapter = new ArrayAdapter<String>(getActivity(), R.layout.list_item_forecast, R.id.list_item_forecast_textview, x);
        final ListView listview = (ListView) rootview.findViewById(R.id.list_view_forecast);
        listview.setAdapter(weather_adapter);
        listview.setOnItemClickListener(new AdapterView.OnItemClickListener()
        {
            public void onItemClick(AdapterView<?> adapterView,View view,int i,long l)
            {
                String msg=(String)listview.getItemAtPosition(i);
                Intent it=new Intent(getActivity(),Detail_Activity.class).putExtra(Intent.EXTRA_TEXT,msg);
                startActivity(it);
            }
        });
        return rootview;
    }
    public void onCreateOptionsMenu(Menu menu,MenuInflater inflater)
    {
        inflater.inflate(R.menu.forecast_fragment, menu);
    }
    public void onStart()
    {
        super.onStart();
        updateweather();
    }
    private void updateweather()
    {
        FetchWeatherTask w=new FetchWeatherTask(getActivity());
        SharedPreferences prefs= PreferenceManager.getDefaultSharedPreferences(getActivity());
        String location = prefs.getString(getString(R.string.pref_location_key),
                getString(R.string.pref_location_default));
        w.execute(location);
    }
    public boolean onOptionsItemSelected(MenuItem item)
    {
        int id=item.getItemId();
        if(id==R.id.action_refresh) {
            FetchWeatherTask w=new FetchWeatherTask(getActivity());
            SharedPreferences prefs= PreferenceManager.getDefaultSharedPreferences(getActivity());
            String location = prefs.getString(getString(R.string.pref_location_key),
                    getString(R.string.pref_location_default));
            w.execute(location);
            return true;
        }
        if (id == R.id.action_settings) {
            startActivity(new Intent(getActivity(), SettingsActivity.class));
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
class FetchWeatherTask extends AsyncTask<String ,Context,String []>
{private Context mContext;
    public FetchWeatherTask(Context context) {
        this.mContext = context;
    }
    @Override
    protected String [] doInBackground(String []params)
    {
        HttpURLConnection urlConnection = null;
        BufferedReader reader = null;
        String forecastJsonStr = null;
        String format="json";
        String units="metric";
        int numDays=7;
        try {
            final String FORECAST_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 DAYS_PARAM="cnt";
            Uri builtUri=Uri.parse(FORECAST_BASE_URL).buildUpon()
                    .appendQueryParameter(QUERY_PARAM,params[0])
                    .appendQueryParameter(FORMAT_PARAM,format)
                    .appendQueryParameter(UNITS_PARAM,units)
                    .appendQueryParameter(DAYS_PARAM,Integer.toString(numDays))
                    .build();
            URL url = new URL(builtUri.toString());
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();
            InputStream inputStream = urlConnection.getInputStream();
            StringBuffer buffer = new StringBuffer();
            if (inputStream == null) {
                return null;
            }
            reader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line + "\n");
            }
            if (buffer.length() == 0) {
                return null;
            }
            forecastJsonStr = buffer.toString();
        } catch (IOException e) {
            Log.e("PlaceholderFragment", "Error ", e);
            return null;
        } finally{
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (final IOException e) {
                    Log.e("PlaceholderFragment", "Error closing stream", e);
                }
            }
        }

        try
        {
            return getWeatherDataFromJson(forecastJsonStr,numDays);
        }
        catch(JSONException e)
        {

        }
        return null;
    }
    protected void onPostExecute(String[] result) {
        if (result != null) {
            MainActivityFragment.weather_adapter.clear();
            for(String dayForecastStr : result) {
                MainActivityFragment.weather_adapter.add(dayForecastStr);
            }
        }
    }
    private String getReadableDateString(long time){
        SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("EEE MMM dd");
        return shortenedDateFormat.format(time);
    }
    private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
            throws JSONException
    {
        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);
        Time dayTime = new Time();
        dayTime.setToNow();
        int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);
        dayTime = new Time();
        String[] resultStrs = new String[numDays];
        for(int i = 0; i < weatherArray.length(); i++) {
            String day;
            String description;
            String highAndLow;
            JSONObject dayForecast = weatherArray.getJSONObject(i);
            long dateTime;
            dateTime = dayTime.setJulianDay(julianStartDay+i);
            day = getReadableDateString(dateTime);
            JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
            description = weatherObject.getString(OWM_DESCRIPTION);
            JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
            double high = temperatureObject.getDouble(OWM_MAX);
            double low = temperatureObject.getDouble(OWM_MIN);
            String HL=formatHighLows(high,low);
            resultStrs[i] = day + " - " + description + " - " +HL;
        }
        return resultStrs;
    }
    public String formatHighLows(double high, double low) {
        MainActivityFragment obj=new MainActivityFragment();

        SharedPreferences sharedPrefs=PreferenceManager.getDefaultSharedPreferences(mContext);
        String unitType=sharedPrefs.getString(mContext.getString(R.string.pref_units_key),mContext.getString(R.string.pref_units_metric));
        if(unitType.equals(mContext.getString(R.string.pref_units_imperial)))
        {
            high=(high*1.8)+32;
            low=(low*1.8)+32;
        }
        else if(!unitType.equals(mContext.getString(R.string.pref_units_metric)))
        {
            Toast.makeText(mContext,"invalid unit",Toast.LENGTH_SHORT).show();
        }
        long roundedHigh = Math.round(high);
        long roundedLow = Math.round(low);
        String str= roundedHigh+"/"+roundedLow;
        return str;
    }
}

3 个答案:

答案 0 :(得分:3)

openweathermap api现在需要API密钥。这改变了上周。如果您最近运行过您的应用,则很可能会在日志中看到错误:

java.io.FileNotFoundException:http://api.openweathermap.org/data/2.5/forecast/daily?q= ...

如果您发现此异常,并且未记录此异常,则最终可能会显示空白列表视图,因为没有值可以填充它。

答案 1 :(得分:0)

在for循环之后的onPostExecute()方法之后对数组适配器执行notifyDataSetChanged()。

        if (result != null) {
            MainActivityFragment.weather_adapter.clear();
            for(String dayForecastStr : result) {
                MainActivityFragment.weather_adapter.add(dayForecastStr);
            }
            //also print size of result using logcat to check.                 
            //Do notifydata set change here.
        }

答案 2 :(得分:0)

我刚遇到同样的问题。对我有用的是在基本URL之后立即将密钥附加到Uri。因此,它应该类似于以下内容,其中key等于openweathermap.org网站上给出的API密钥,“KEY_PARAM”等于“APPID”。

final String FORECAST_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 DAYS_PARAM = "cnt";
final String KEY_PARAM = "APPID";

        Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
                .appendQueryParameter(KEY_PARAM, key)
                .appendQueryParameter(QUERY_PARAM, params[0])
                .appendQueryParameter(FORMAT_PARAM, format)
                .appendQueryParameter(UNITS_PARAM, units)
                .appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
                .build();