Приложение не отправляет запрос к интернет-ресурсу android 10+
Пишу парсер погоды на java для android и при тестировании на устройстве с версией android 5 запрос отправляется и приложение получает необходимые данные. Но на android 10 и выше приложение вместо объекта возвращает null.
Код класса, который отправляет запрос и возвращает JSON объект
package com.example.weatherapp;
import android.content.Context;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
//RemoteFetch отвечает за получение данных о погоде через API сервиса OpenWeather
public class RemoteFetch {
private static final String OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?q=%s&appid=0b9f2ad4f3628fb953da7636aa67d130&units=metric";
public static JSONObject getJSON(Context context, String city) throws JSONException {
// Создаем подключение к сервису OpenWeather
try{
URL url = new URL(String.format(OPEN_WEATHER_MAP_API, city));
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
// Получаем данные в виде строк
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuffer json = new StringBuffer(1024);
String tmp = "";
// Записываем данные в переменную для последующего перевода в JSON объект
while((tmp=reader.readLine())!=null){
json.append(tmp).append("\n");
}
reader.close();
JSONObject data = new JSONObject(json.toString());
// Если код ответа не равен 200, то данные не будут получены
if(data.getInt("cod") != 200){
return null;
}
return data;
}catch(Exception e){
return null;
}
}
}
Код фрагмента
package com.example.weatherapp;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.support.v4.app.Fragment;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.DateFormat;
import java.util.Date;
public class FragmentWeather extends Fragment implements View.OnClickListener {
// Блок переменных для связи с элементами интерфейса
TextView city_name_field;
TextView city_temperature_field;
TextView city_rain_field;
TextView city_updated_time_field;
TextView city_description_field;
EditText city;
Button button;
Handler handler;
public FragmentWeather(){
handler = new Handler();
}
@Override
public void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
View rootView = inflater.inflate(R.layout.fragment_weather, container, false);
// Ниже задаются значения переменных для связи с элементами интерфейса
city_name_field = (TextView)rootView.findViewById(R.id.city_name_field);
city_updated_time_field= (TextView)rootView.findViewById(R.id.city_updated_time_field);
city_description_field = (TextView)rootView.findViewById(R.id.city_description_field);
city_temperature_field = (TextView)rootView.findViewById(R.id.city_temperature_field);
city_rain_field = (TextView)rootView.findViewById(R.id.city_rain_field);
button = (Button)rootView.findViewById(R.id.button);
button.setOnClickListener(this);
city = (EditText) rootView.findViewById(R.id.input);
return rootView;
}
public static boolean isOnline(Context context)
{
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting())
{
return true;
}
return false;
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
// Метод updateWeatherData получает в качестве аргумента строку с названием города на английском языке.
// Используется для получения данных о погоде из класса RemoteFetch.
private void updateWeatherData(String city){
// Создаем отдельный поток для получения данных.
// Если данные получены, то используем метод renderWeather, если нет - выводим высплывающее сообщение об ошибке.
new Thread(){
public void run() {
final JSONObject json;
try {
json = RemoteFetch.getJSON(getActivity(), city);
if (json == null) {
handler.post(new Runnable() {
public void run() {
Toast.makeText(getActivity(), getActivity().getString(R.string.city_not_found), Toast.LENGTH_LONG).show();
}
});
} else {
handler.post(new Runnable() {
public void run() {
renderWeather(json);
}
});
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}.start();
}
// Метод renderWeather используется для отрисовки и изменения интерфейса.
// В качестве аргумента получает JSON объект с данными о погоде.
private void renderWeather(JSONObject json){
try{
// В этом блоке происходит замена текста элементов интерфейса на данные о погоде, полученные из полей JSON объекта.
city_name_field.setText(json.getString("name").toUpperCase()+", "+json.getJSONObject("sys").getString("country"));
JSONObject description = json.getJSONArray("weather").getJSONObject(0);
JSONObject main = json.getJSONObject("main");
city_description_field.setText(description.getString("description").toUpperCase()+"\n"+"Влажность: "+main.getString("humidity")+"%"+"\n"+"Давление: "+main.getString("pressure")+"hPa");
city_temperature_field.setText(String.format("%.2f", main.getDouble("temp"))+"℃");
DateFormat dateFormat = DateFormat.getDateTimeInstance();
String updated_time = dateFormat.format(new Date(json.getLong("dt")*1000));
city_updated_time_field.setText("Последнее обновление: " + updated_time);
setWeather(description.getInt("id"), json.getJSONObject("sys").getLong("sunrise")*1000, json.getJSONObject("sys").getLong("sunset")*1000);
}catch(Exception e){
Log.e("WeatherApp", "Один или несколько полей не были найдены в json");
}
}
// Метод setWeather в качестве аргументов получает три числа: id, время восхода и время заката.
// Используется для выбора иконки погодных условий
private void setWeather(Integer actualId, long sunrise, long sunset){
int id = actualId/100;
String icon = "";
if(actualId == 800){
long currentTime = new Date().getTime();
if(currentTime>=sunrise && currentTime<sunset){
icon = getActivity().getString(R.string.sunny);
}
}else{
switch(id){
case 2:
icon = getActivity().getString(R.string.thunder);
break;
case 3:
icon = getActivity().getString(R.string.drizzle);
break;
case 5:
icon = getActivity().getString(R.string.rainy);
break;
case 6:
icon = getActivity().getString(R.string.snowy);
break;
case 7:
icon = getActivity().getString(R.string.foggy);
break;
case 8:
icon = getActivity().getString(R.string.cloudy);
break;
}
}
city_rain_field.setText(icon);
}
// В переопределенном методе onClick вызываем метод updateWeatherData для получения и отрисовки данных о погоде.
@Override
public void onClick(View v) {
if ( !isOnline(getContext()) ){
Toast.makeText(getActivity(), "No internet connection", Toast.LENGTH_LONG).show();
}else{
updateWeatherData(city.getText().toString());
}
}
}