Search code examples
javaandroidwidget

Weather widget in Java in Android Studio


I wrote a widget in Java in Android Studio. This widget takes and displays the weather from an api from the internet. The problem is that this widget stops working after staying on the phone for a while or as soon as the phone is turned off and on and does not show any reaction. What should I do to solve this problem?

When the WeatherApiClient.java class is called, it reads the weather from the Internet, and the widget_size_1.java class loads the information in the widget.

widget_size_1.java

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.util.Log;
import android.widget.RemoteViews;
import androidx.annotation.NonNull;
import java.text.DecimalFormat;

public class widget_size_1 extends AppWidgetProvider {

    String temp, city, desc;

    public void updateAppWidget(@NonNull Context context, String shahr, String temp, String desc, int appWidgetId) {
        // Construct the RemoteViews object
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_size_1);
        views.setTextViewText(R.id.widget_city, shahr);
        views.setTextViewText(R.id.widget_desc, desc);
        views.setTextViewText(R.id.widget_temp, temp);

        // Setting up the onClickListener for the refresh icon
        Intent intent = new Intent(context, widget_size_1.class);
        intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{appWidgetId});

        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
        views.setOnClickPendingIntent(R.id.widget_refresh, pendingIntent);

        // Instruct the widget manager to update the widget
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

    @Override public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);

        // Handling the onClick event for the refresh icon
        if (intent.getAction() != null && intent.getAction().equals(AppWidgetManager.ACTION_APPWIDGET_UPDATE)) {
            for (int appWidgetId : appWidgetIds)
                resetWidget(context, appWidgetId);
            performBtnSetAction(context);

            // Update the widget views (if needed)
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
            if (appWidgetIds != null) {
                onUpdate(context, appWidgetManager, appWidgetIds);
            }
        }
    }

    private void performBtnSetAction(@NonNull Context context) {
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_size_1);
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, widget_size_1.class));
        
        onUpdate(context, appWidgetManager, appWidgetIds);

        for (int appWidgetId : appWidgetIds)
            currentLocTempReader(context);
    }
    
    public void currentLocTempReader(@NonNull Context context) {
        @SuppressLint("SetTextI18n")
        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        GpsClass gpsClass = new GpsClass(locationManager, context);
        Location location = gpsClass.getLocation2();
        LinkCreator linkCreator = new LinkCreator(context);
        WeatherApiClient weatherApiClient = new WeatherApiClient("base url");

        weatherApiClient.getCurrentWeatherData(location.getLatitude(),location.getLongitude(),linkCreator.GetOWMApiKey(), new WeatherApiClient.WeatherCallback() {
            @Override
            public void onSuccess(WeatherData weatherData) {
                city = weatherData.getName();
                DecimalFormat decimalFormat = new DecimalFormat("#,##0.00");
                temp = decimalFormat.format(weatherData.getMain().getTemp());
                desc = weatherData.getWeather()[0].getDescription();
                setDataToWidget(context);
                Log.i("MyWidgetLogs", " ok");
            }

            @Override
            public void onFailure(Throwable throwable) {
                Log.e("MyWidgetLogs", throwable.toString());
            }
        });
    }

    private void setDataToWidget(Context context) {
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, widget_size_1.class));
        
        for (int appWidgetId : appWidgetIds)
            updateAppWidget(context, city, temp, desc, appWidgetId);
    }

    public void resetWidget(Context context, int appWidgetId) {
        // Construct the RemoteViews object
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_size_1);
        views.setTextViewText(R.id.widget_city, "Loading...");
        views.setTextViewText(R.id.widget_desc, "Loading...");
        views.setTextViewText(R.id.widget_temp, "Loading...");

        // Setting up the onClickListener for the refresh icon
        Intent intent = new Intent(context, widget_size_1.class);
        intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{appWidgetId});

        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
        views.setOnClickPendingIntent(R.id.widget_refresh, pendingIntent);

        // Instruct the widget manager to update the widget
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        appWidgetManager.updateAppWidget(appWidgetId, views);
        performBtnSetAction(context);
    }

    @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, @NonNull int[] appWidgetIds) {
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, city, temp, desc, appWidgetId);
        }
    }

    @Override public void onEnabled(Context context) {}
    @Override public void onDisabled(Context context) {}
}

WeatherApiClient.java

import android.util.Log;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;

public class WeatherApiClient {

    private final WeatherApi weatherApi;

    public WeatherApiClient(String baseURL) {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseURL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        weatherApi = retrofit.create(WeatherApi.class);
        mytest();
    }

    public void getCurrentWeatherData(
            double lat, double lon, String apiKey, final WeatherCallback callback) {
        String url = "weather?lat=" + lat + "&lon=" + lon + "&appid=" + apiKey;

        Call<WeatherData> call = weatherApi.getWeatherData(url);
        try {
            call.enqueue(new Callback<WeatherData>() {
                @Override
                public void onResponse(Call<WeatherData> call, Response<WeatherData> response) {
                    if (response.isSuccessful()) {
                        WeatherData weatherData = response.body();
                        callback.onSuccess(weatherData);
                    } else {
                        callback.onFailure(new Exception("Response not successful"));
                    }
                }

                @Override
                public void onFailure(Call<WeatherData> call, Throwable t) {
                    callback.onFailure(t);
                }
            });
        } catch (Throwable e) {
            Log.e(MainActivity.myExceptionTag + " Callback<WeatherData>", e.toString());
        }
    }

    protected void mytest() {

        TestApiClient testApiClient = new TestApiClient("https://www.stackoverflow.com");

        testApiClient.getTestData(new TestCallback() {
            @Override
            public void onSuccess(Object data) {
                Log.d("TestApiClient", "Response: " + data.toString());
            }

            @Override
            public void onFailure(Throwable throwable) {
                Log.e("TestApiClient", "Error: " + throwable.toString());
            }
        });
    }

    public class TestApiClient {

        private final TestApi testApi;

        public TestApiClient(String baseUrl) {
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();

            testApi = retrofit.create(TestApi.class);
        }

        public void getTestData(final TestCallback callback) {
            Call<Object> call = testApi.getTestData();
            call.enqueue(new retrofit2.Callback<Object>() {
                @Override
                public void onResponse(Call<Object> call, retrofit2.Response<Object> response) {
                    if (response.isSuccessful()) {
                        callback.onSuccess(response.body());
                    } else {
                        callback.onFailure(new Exception("Response not successful"));
                    }
                }

                @Override
                public void onFailure(Call<Object> call, Throwable t) {
                    callback.onFailure(t);
                }
            });
        }
    }

    public interface TestCallback {
        void onSuccess(Object data);
        void onFailure(Throwable throwable);
    }

    public interface TestApi {
        @GET("/posts/1")
        Call<Object> getTestData();
    }

    public interface WeatherCallback {
        void onSuccess(WeatherData weatherData);

        void onFailure(Throwable throwable);
    }
}

The internet status has been checked and the internet is active The api status has been checked and is active


Solution

  • The program must disable the battery optimizer in Android for itself so that it is not thrown out of memory. Also, foreground Service should be activated every time it is used.