我正在关注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();
}
}
这是该应用的屏幕截图:
答案 0 :(得分:1)
通过查看代码,有几件事情是错误的。
您在OnCreate和onResume中调用了getLocation方法,这在逻辑上是不正确的。只有当您希望经常获得位置时,才能将其保留在onResume上。
当我们调用getLocation方法时,它不能保证直接给出纬度和经度,它取决于提供者(位置管理器的Read API)需要它自己的甜蜜时间因此你的第一次调用getForecast可能会失败。
解决方案:调用onLocationChange方法时可以调用getForecast方法,到那时你可以显示progressDialog。
确保您已在清单文件中提供了与位置相关的权限