从onChangeListener更新视图到某个位置

时间:2015-05-19 12:05:19

标签: android location

我正在关注Android天气应用教程,其中天气应用程序使用API​​请求有关场所的更多信息; 但是,该应用程序不是“#34;位置感知"所以我决定尝试这样做,但是当我的应用程序被创建时,它会使用硬编码坐标(私有纬度和经度)调用API。我不明白为什么会发生这种情况,我在getForecast方法之前调用getLoation方法。 getLocation方法应该使用位置管理器的互联网提供商,并在调用getForecast之前设置纬度和经度(使用坐标进行异步API调用)。奇怪的是,当我按下刷新按钮时,从位置管理器获取位置坐标,并且getLocationName也正常工作(使用坐标找到位置的名称并设置locationLabel的位置)这个名字。)

我怀疑e问题是因为如果我用来进行异步调用的OkHTTP API使用工作线程。

NODE:我正在使用Butter刀和YoYo API,我还有四个类,它们存储有关天气的信息,称为预测,小时和当前和日。我没有包含它们,因为我认为这不重要,因为问题出在我的主要活动类

以下是我的主要活动类中的代码:

public static final String TAG = MainActivity.class.getSimpleName();
private Forecast mForecast;
//default coordinates - Aberdeen, UK Lati:57.156866 ; Long:
private double latitude = 57.156866;
private double longitude = -2.094278;
private LocationManager locationManager;

@InjectView(R.id.timeLabel) TextView mTimeLabel;
@InjectView(R.id.temperatureLabel) TextView mTemperatureLabel;
@InjectView(R.id.humidityValue) TextView mHumidityValue;
@InjectView(R.id.precipValue) TextView mPrecipValue;
@InjectView(R.id.summaryLabel) TextView mSummaryLabel;
@InjectView(R.id.locationLabel) TextView mLocationLabel;
@InjectView(R.id.windSpeedValue) TextView mWindSpeedValue;
@InjectView(R.id.iconImageView) ImageView mIconImageView;
@InjectView(R.id.refreshImageView) ImageView mRefreshImaveView;
@InjectView(R.id.progressBar) ProgressBar mProgressBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ButterKnife.inject(this);
    mProgressBar.setVisibility(View.INVISIBLE);
    mRefreshImaveView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            getLocation();
            getForecast(latitude, longitude);
        }
    });
    getLocation();
    getForecast(latitude, longitude);

}

@Override
protected void onResume() {
    super.onResume();
    getForecast(latitude, longitude);
}

private void getForecast(double latitude, double longitude) {
    //animations
    YoYo.with(Techniques.FadeIn).duration(1800).playOn(mLocationLabel);
    YoYo.with(Techniques.FadeIn).duration(1600).playOn(mTemperatureLabel);
    YoYo.with(Techniques.FadeIn).duration(1800).playOn(mIconImageView);
    YoYo.with(Techniques.FadeIn).duration(1000).playOn(mSummaryLabel);
    YoYo.with(Techniques.FadeIn).duration(1200).playOn(mHumidityValue);
    YoYo.with(Techniques.FadeIn).duration(1400).playOn(mWindSpeedValue);
    YoYo.with(Techniques.FadeIn).duration(1200).playOn(mPrecipValue);
    YoYo.with(Techniques.FadeIn).duration(1200).playOn(mTimeLabel);

    String API_KEY = "API_KEY";
    String forecast = "https://api.forecast.io/forecast/"+ API_KEY +"/"+ latitude+","+ longitude+"?units=auto";

    if(isNetworkAvailable()) {
        toggleRefresh();

        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(forecast)
                .build();

        Call call = client.newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        toggleRefresh();
                    }
                });
                alertUserAboutError();
            }
            //when the call to the Okhttp library finishes, than calls this method:
            @Override
            public void onResponse(Response response) throws IOException {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        toggleRefresh();
                    }
                });
                try {
                    String jsonData = response.body().string();
                    //Log.v(TAG, jsonData);
                    if (response.isSuccessful()) {
                       mForecast = parseForecastDetails(jsonData);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                updateDisplay();
                            }
                        });


                    } else {
                        alertUserAboutError();
                    }
                } catch (IOException | JSONException e) {
                    Log.e(TAG, "Exception caught:", e);
                }
            }
        });
    }else{
        //Toast.makeText(this,getString(R.string.network_unavailable_message),Toast.LENGTH_LONG).show();
        WIFIDialogFragment dialog = new WIFIDialogFragment();
        dialog.show(getFragmentManager(), getString(R.string.error_dialog_text));
    }
}

private void toggleRefresh() {
    if(mProgressBar.getVisibility() == View.INVISIBLE){
        mProgressBar.setVisibility(View.VISIBLE);
        mRefreshImaveView.setVisibility(View.INVISIBLE);
    }else{
        mProgressBar.setVisibility(View.INVISIBLE);
        mRefreshImaveView.setVisibility(View.VISIBLE);
    }
}
//updates the dysplay with the data in the CUrrentWeather locaal object
private void updateDisplay() {
    Current current = mForecast.getCurrent();
    //setting the current weather details to the ui
    mTemperatureLabel.setText(current.getTemperature()+"");
    mTimeLabel.setText("At "+ current.getFormattedTime()+" it will be");
    mHumidityValue.setText(current.getHumidity() +"%");
    mPrecipValue.setText(current.getPrecipChange()+"%");
    mSummaryLabel.setText(current.getSummery());
    mWindSpeedValue.setText(current.getWindSpeed()+"");
    mLocationLabel.setText(current.getTimeZone());
    //sets the mLocationLavel to the appropriate name and not the timezome from the  API
    getLocationName();
    Drawable drawable = ContextCompat.getDrawable(this, current.getIconId());
    mIconImageView.setImageDrawable(drawable);


}

private Forecast parseForecastDetails(String jsonData) throws JSONException {
    Forecast forecast = new Forecast();
    forecast.setCurrent(getCurrentDetails(jsonData));
    forecast.setHourlyForecast(getHourlyForecast(jsonData));
    forecast.setDailyForecast(getDailyForecast(jsonData));

    return forecast;
}

private Day[] getDailyForecast(String jsonData) throws JSONException{
    JSONObject forecast = new JSONObject(jsonData);
    String timezone = forecast.getString("timezone");
    JSONObject daily = forecast.getJSONObject("daily");
    JSONArray data = daily.getJSONArray("data");

    Day[] days = new Day[data.length()];

    for(int i = 0;i < data.length();i++){
        JSONObject jsonDay = data.getJSONObject(i);
        Day day = new Day();

        day.setSummary(jsonDay.getString("summary"));
        day.setIcon(jsonDay.getString("icon"));
        day.setTemperatureMax(jsonDay.getDouble("temperatureMax"));
        day.setTime(jsonDay.getLong("time"));
        day.setTimezone(timezone);

        days[i] = day;

        Log.v(MainActivity.class.getSimpleName(),days[i].getIcon());
    }

    return days;
}

private Hour[] getHourlyForecast(String jsonData) throws JSONException{
    JSONObject forecast = new JSONObject(jsonData);
    String timezone = forecast.getString("timezone");
    JSONObject hourly = forecast.getJSONObject("hourly");
    JSONArray data = hourly.getJSONArray("data");

    Hour[]hours = new Hour[data.length()];

    for(int i = 0;i < data.length();i++){
        JSONObject jsonHour = data.getJSONObject(i);
        Hour hour = new Hour();

        hour.setSummary(jsonHour.getString("summary"));
        hour.setTemperature(jsonHour.getDouble("temperature"));
        hour.setIcon(jsonHour.getString("icon"));
        hour.setTime(jsonHour.getLong("time"));
        hour.setTimezone(timezone);

        hours[i] = hour;
    }

    return hours;
}

/*
 * throws JSONException, doing it like that, we place the
 * responsability of handaling this exeption to the caller of the method
*/
private Current getCurrentDetails(String jsonData) throws JSONException{
    JSONObject forecast = new JSONObject(jsonData);
    String timezone = forecast.getString("timezone");
    Log.i(TAG,"From JSON: " + timezone);

    JSONObject currently = forecast.getJSONObject("currently");
    Current mCurrent = new Current();
    mCurrent.setHumidity(currently.getDouble("humidity"));
    mCurrent.setTime(currently.getLong("time"));
    mCurrent.setIcon(currently.getString("icon"));
    mCurrent.setPrecipChange(currently.getDouble("precipProbability"));
    mCurrent.setSummery(currently.getString("summary"));
    mCurrent.setTemperature(currently.getDouble("temperature"));
    mCurrent.setTimeZone(timezone);
    mCurrent.setWindSpeed(currently.getDouble("windSpeed"));

    Log.d(TAG, mCurrent.getFormattedTime());
    return mCurrent;
}

private boolean isNetworkAvailable() {
    ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = manager.getActiveNetworkInfo();
    boolean isAvailable = false;
    //contition to check if there is a network and if the device is connected
    if(networkInfo != null && networkInfo.isConnected()){
        isAvailable = true;
    }

    return isAvailable;
}

private void alertUserAboutError() {
    AlertDIalogFragment dialog = new AlertDIalogFragment();
    dialog.show(getFragmentManager(),getString(R.string.error_dialog_text));
}
private void getLocation(){

locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

if(isNetworkAvailable()){
    locationManager.requestLocationUpdates(
            LocationManager.NETWORK_PROVIDER, 1, 1000, new MyLocationListener());
}else{
    WIFIDialogFragment dialog = new WIFIDialogFragment();
    dialog.show(getFragmentManager(), getString(R.string.error_dialog_text));
}

}     私有类MyLocationListener实现LocationListener {

    @Override
    public void onLocationChanged(Location loc) {
        latitude = loc.getLatitude();
        longitude = loc.getLongitude();
        Toast.makeText(MainActivity.this,
                "Location changed: Lat: " + loc.getLatitude() + " Lng: "
                        + loc.getLongitude(), Toast.LENGTH_SHORT).show();
        locationManager.removeUpdates(this);
    }

    @Override
    public void onProviderDisabled(String provider) {}

    @Override
    public void onProviderEnabled(String provider) {}

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {}
}

private void getLocationName(){
    Geocoder geo = new Geocoder(this, Locale.getDefault());
    try {
        List<Address> addressList = geo.getFromLocation(this.latitude,this.longitude,1);
        if (addressList.isEmpty()){
            //gets the default name from the timeZone
            //that we set in as a local variable
        }else{
            if(addressList.size() > 0){
                Log.v(MainActivity.class.getSimpleName(),addressList.get(0).getLocality() + ", "+ addressList.get(0).getCountryName()+"");
                mLocationLabel.setText(addressList.get(0).getLocality() + ", "+ addressList.get(0).getCountryName());
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

这是该应用的屏幕截图: enter image description here

1 个答案:

答案 0 :(得分:1)

通过查看代码,有几件事情是错误的。

  1. 您在OnCreate和onResume中调用了getLocation方法,这在逻辑上是不正确的。只有当您希望经常获得位置时,才能将其保留在onResume上。

  2. 当我们调用getLocation方法时,它不能保证直接给出纬度和经度,它取决于提供者(位置管理器的Read API)需要它自己的甜蜜时间因此你的第一次调用getForecast可能会失败。

  3. 解决方案:调用onLocationChange方法时可以调用getForecast方法,到那时你可以显示progressDialog。

  4. 确保您已在清单文件中提供了与位置相关的权限