Как из Asynctask получить доступ к MainActivity

171
15 декабря 2017, 02:40

Мне нужна помощь, создал приложение погода, вот код

Класс Weather

public class Weather extends AsyncTask<String, Void, String> {
private String result = "";
private HttpURLConnection urlConnection = null;
@Override
protected String doInBackground(String... urls) {
    try {
        URL url = new URL(urls[0]);
        urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.connect();
        InputStream inputStream = urlConnection.getInputStream();
        InputStreamReader reader = new InputStreamReader(inputStream);
        int data = reader.read();
        while (data != -1) {
            char current = (char) data;
            result = result.concat(String.valueOf(current));
            data = reader.read();
        }
        return result;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        urlConnection.disconnect();
    }
    return null;
}

@SuppressLint("SetTextI18n")
@Override
protected void onPostExecute(String result) {
    super.onPostExecute(result);
    try {
        JSONObject jsonObject = new JSONObject(result);
        JSONObject info = new JSONObject(jsonObject.getString("main"));
        JSONObject wind = new JSONObject(jsonObject.getString("wind"));
        double temperature = Double.parseDouble(info.getString("temp"));
        int temp_Celsius = (int) (temperature - 273.15);
        String pressure = info.getString("pressure");
        String humidity = info.getString("humidity");
        String windSpeed = wind.getString("speed");
        String place = jsonObject.getString("name");
        String weather = jsonObject.getString("weather");
        JSONArray array = new JSONArray(weather);
        String description = "";
        int id = 0;
        for (int i = 0; i < array.length(); i++) {
            JSONObject arrayObject = array.getJSONObject(i);
            description = arrayObject.getString("description");
            id = arrayObject.getInt("id");
        }
        setWeatherIcon(id, jsonObject.getJSONObject("sys").getLong("sunrise") * 1000,
                jsonObject.getJSONObject("sys").getLong("sunset") * 1000);
        MainActivity.city.setText(place.toUpperCase());
        MainActivity.temperature.setText(String.valueOf(temp_Celsius + "°C"));
        MainActivity.details.setText("Weather: " + description + "\n" + "Pressure: " + pressure + "hpa" + "\n" + "Humidity: " + humidity + "\n" + "Wind speed: " + windSpeed + "m/s");
    } catch (Exception e) {
        e.printStackTrace();
    }
}
private void setWeatherIcon(int actualId, long sunrise, long sunset) {
    int id = actualId / 100;
    long currentTime = new Date().getTime();
    if (actualId == 800) {
        if (currentTime >= sunrise && currentTime < sunset) {
            MainActivity.imageView.setImageResource(R.drawable.sun);
        } else MainActivity.imageView.setImageResource(R.drawable.night);
    } else {
        if (currentTime >= sunrise && currentTime < sunset) {
            switch (id) {
                case 7:
                    MainActivity.imageView.setImageResource(R.drawable.partly_cloudy);
                    break;
            }
        } else if (currentTime <= sunrise && currentTime > sunset) {
            switch (id) {
                case 7:
                    MainActivity.imageView.setImageResource(R.drawable.night_cloudy);
                    break;
            }
        } else switch (id) {
            case 2:
                MainActivity.imageView.setImageResource(R.drawable.thunder);
                break;
            case 3:
                MainActivity.imageView.setImageResource(R.drawable.storm);
                break;
            case 5:
                MainActivity.imageView.setImageResource(R.drawable.rain);
                break;
            case 6:
                MainActivity.imageView.setImageResource(R.drawable.snow);
                break;
            case 8:
                MainActivity.imageView.setImageResource(R.drawable.cloud);
                break;
        }
    }
}}

Класс Main

public class MainActivity extends AppCompatActivity {
@SuppressLint("StaticFieldLeak")
public static TextView city;
@SuppressLint("StaticFieldLeak")
public static TextView temperature;
@SuppressLint("StaticFieldLeak")
public static TextView details;
@SuppressLint("StaticFieldLeak")
public static ImageView imageView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    city = findViewById(R.id.city);
    temperature = findViewById(R.id.temperature);
    details = findViewById(R.id.details);
    imageView = findViewById(R.id.weather_icon);
    try {
        Weather weather = new Weather();
        weather.execute("http://api.openweathermap.org/data/2.5/weather?q=Yerevan&appid=53328692679f840d7be7c1d520a324d1").get();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu, menu);
    return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.change_city) {
        showInputDialog();
    }
    return false;
}
private void showInputDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Change city");
    final EditText inputCity = new EditText(this);
    inputCity.setInputType(InputType.TYPE_CLASS_TEXT);
    builder.setView(inputCity);
    builder.setPositiveButton("Change", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            try {
                Weather weather = new Weather();
                weather.execute("http://api.openweathermap.org/data/2.5/weather?q=" + inputCity.getText().toString() +
                        "&appid=53328692679f840d7be7c1d520a324d1").get();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
    builder.show();
}

}

Есть 2 класса, вы это уже видите) но там есть несколько View элементов в MainActivity (TextView, ImageView), и их я использую в классе Weather, но их надо делать статик в MainActivity, а так код нечистый... как можно решить эту проблему??

Answer 1

Один из вариантов сделать класс Weather внутренним нестатическим классом MainActivity и тогда в нём будет неявная ссылка на класс активити MainActivity.this, через которую вы сможете получить доступ к её полям.

Другой вариант, явно передать объект MainActivity в класс Weather через конструктор Weather weather = new Weather(this);, сохранить в локальную переменную и обращаться к её полям.

public class Weather extends AsyncTask<String, Void, String> {
    ...
    private MainActivity activity;
    public Weather(MainActivity activity) {
        this.activity = activity;
    }
    @Override
    protected void onPostExecute(String result) {
        ...
        if (activity != null) {
            activity.city.setText(place.toUpperCase());
            activity.temperature.setText(String.valueOf(temp_Celsius + "°C"));
            activity.details.setText("Weather: " + description + "\n" + "Pressure: " + pressure + "hpa" + "\n" + "Humidity: " + humidity + "\n" + "Wind speed: " + windSpeed + "m/s");
        }
        ...
    }
    public void release() {
        activity = null;
    }
}

В MainActivity:

private Weather weather;
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    weather = new Weather(this);
    ...
}
@Override
protected void onDestroy() {
    super.onDestroy();
    weather.release();
}

В первом варианте вы можете получить утечку активити пока не будет завершено выполнение AsyncTask. Во втором вы можете этого избежать, вручную зануляя ссылку на активити, например, в методе onDestroy(). Но при этом при обращении к её полям нужно будет добавить проверку на null.

READ ALSO
Как создать свой интерфейс для RX?

Как создать свой интерфейс для RX?

Как создать интерфейс и добавить туда весь код который находиться в методе create?

220
Принятия и отправка файлов по сокетах

Принятия и отправка файлов по сокетах

Здравствуйте, как мне организовать одновременное принятия и отправку файлов по сокетах? Подскажите алгоритм принятия и отправки файлов

193
SIP server на java с использованием Datagram

SIP server на java с использованием Datagram

Есть готовый сервер на java с использованием Datagram https://githubcom/srajat/UDP-SIP-Server но он то падает, потому что строки парсит неправильно, то запросы шлет...

176
Отсортировать массив java

Отсортировать массив java

Не могу отсортировать массив (скорее всего нужен по убыванию)В задании стоит задача вывести двух самых высоких людей, то есть найти два максимальных...

175