Как сохранить состояние темного режима в Android, когда приложение полностью закрыто

У меня небольшая проблема. Когда я включаю темный режим в своем приложении, а затем полностью закрываю приложение в Android, когда я снова открываю его, оно возвращается в светлый режим. Для этого я использую AppCompatDelegate. У меня есть фрагмент настроек с переключателем для включения или выключения темного режима, и он хорошо работает. У меня есть общие настройки для этого фрагмента переключателя, и он работает. Единственная проблема заключается в том, что остальная часть приложения не остается в темном режиме после полного закрытия, а затем снова открывается. Есть ли способ сохранить, а затем восстановить темный режим, когда я закрою и снова открою его?

Вот мой код для MainActivity:

package com.barzalou.lpapineau.test;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.Menu;
import com.barzalou.lpapineau.test.ui.CheckedChangeCallback;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.navigation.NavigationView;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

public class MainActivity extends AppCompatActivity implements CheckedChangeCallback {

    private AppBarConfiguration mAppBarConfiguration;

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

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        mAppBarConfiguration = new AppBarConfiguration.Builder(
            R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow, R.id.nav_maps)
            .setDrawerLayout(drawer)
            .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
        NavigationUI.setupWithNavController(navigationView, navController);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        return NavigationUI.navigateUp(navController, mAppBarConfiguration)
                || super.onSupportNavigateUp();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.action_exit) {
            finish();
            System.exit(0);
        }
        return false;
    }

    public void onCheckedChange(boolean isChecked) {
        if (isChecked) {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
            Log.d("Dark Mode Switch State", "On");
        }
        else {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
            Log.d("Dark Mode Switch State", "Off");
        }
    }

Вот мой код для SettingsFragment:

package com.barzalou.lpapineau.test.ui.settings;

import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import com.barzalou.lpapineau.test.R;
import com.barzalou.lpapineau.test.ui.CheckedChangeCallback;
import android.content.Context;

import static android.content.Context.MODE_PRIVATE;

public class SettingsFragment extends Fragment {

    private SettingsViewModel settingsViewModel;
    private static Switch DarkMode;
    private boolean SwitchOnOff;
    private CheckedChangeCallback callback = null;

    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        settingsViewModel = ViewModelProviders.of(this).get(SettingsViewModel.class);
        View root = inflater.inflate(R.layout.fragment_settings, container, false);
        final TextView textView = root.findViewById(R.id.text_settings);
        settingsViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                textView.setText(s);
            }
        });
        return root;
    }

    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        DarkMode = (Switch) getView().findViewById(R.id.DarkModeSwitch);

        DarkMode.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                callback.onCheckedChange(isChecked);
            }
        });
    }

    public void onAttach(final Activity activity) {
        super.onAttach(activity);
        if (activity instanceof CheckedChangeCallback) {
            this.callback = (CheckedChangeCallback) activity;
        }
    }

    public void onDetach() {
        super.onDetach();
        callback = null;
    }

    //Save and Restore Switch, Buttons, Textboxs, etc -----------------------
    @Override
    public void onStop() {
        super.onStop();
        try {
            saveData();
            Log.d("Data Save", "Data was saved");
        } catch (Exception e) {
            Log.d("Data Save", "Data could not be saved");
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        try {
            loadData();
            updateViews();
            Log.d("Data Restore", "Data was restored");
        } catch (Exception e) {
           Log.d("Data Restore", "Data was not able to get restored");
        }
    }
    //------------------------------------------------------------------------



    // Save data, load data and update views functions -----------------------
    public void saveData() {
        SharedPreferences sharedPreferences = getContext().getSharedPreferences("SharedPrefs", MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();

        // Add other Switches, Buttons, Texboxes, etc to save
        editor.putBoolean("SwitchState", DarkMode.isChecked());
        // Example: editor.putString("String1", textview.getText().toString());

        //---------------------------------------------------

        editor.apply();
    }

    public void loadData() {
        SharedPreferences sharedPreferences = getContext().getSharedPreferences("SharedPrefs", MODE_PRIVATE);
        SwitchOnOff = sharedPreferences.getBoolean("SwitchState", true); //Change true to false to make the switch on by default
    }

    public void updateViews() {
        DarkMode.setChecked(SwitchOnOff);
    }
    //------------------------------------------------------------------------
}

3 ответа

Решение

Я нашел простой и прямой ответ. Я тестировал это несколько раз, чтобы убедиться. Просто добавьте следующие переменные в MainActivity:

int NightMode;
SharedPreferences sharedPreferences;
SharedPreferences.Editor editor;

После этого вы захотите добавить следующие строки в метод MainActivity OnCreate():

sharedPreferences = getSharedPreferences("SharedPrefs", MODE_PRIVATE);
NightMode = sharedPreferences.getInt("NightModeInt", 1);
AppCompatDelegate.setDefaultNightMode(NightMode);

И чтобы закончить это, сохраните все свои переменные в общих настройках с помощью метода OnSaveInstanceState:

@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);

    NightMode = AppCompatDelegate.getDefaultNightMode();

    sharedPreferences = getSharedPreferences("SharedPrefs", MODE_PRIVATE);
    editor = sharedPreferences.edit();

    editor.putInt("NightModeInt", NightMode);
    editor.apply();
}

Это все, что вам нужно сделать, чтобы сохранить состояние темного режима всего вашего приложения, даже когда приложение завершено или убито ОС.

Вы должны установить это в Applicationс onCreate() метод

class MyApp : Application() {

    @Override
    public void onCreate() {
        super.onCreate();
        boolean isNightMode = sharedPreferences.getBoolean("SwitchState", true);
        if (isNightMode) {
          AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
        } else {
       AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
     }
    }
}

Не забываем добавить AndroidManifest

<application
    android:name=".MyApp"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"

(этот код находится в котлине)

в начале приложения (любого) вставьте этот код в основное действие / всплеск активности

      private lateinit var sharedPreferences: SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        sharedPreferences = getSharedPreferences(getString(R.string.app_name), MODE_PRIVATE)
        when (sharedPreferences.getInt("night_mode", 2)) {
            0 -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
            1 -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
            else -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
        }
}

Инициализация диалогового окна onclick выполняется с использованием приведенного ниже кода с использованием общих настроек для изменения темы.

      private fun themeDialog() {
        val items = arrayOf("Light", "Dark", "Auto (System Default)")
        var checkedItem = sharedPreferences.getInt("night_mode", 2)

        MaterialAlertDialogBuilder(this)
            .setTitle("Theme")
            .setPositiveButton("Ok") { dialog, which ->
                when (checkedItem) {
                    0 ->{
                        sharedPreferences.edit().putInt("night_mode", 0).apply()
                        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)}
                    1 -> {
                        sharedPreferences.edit().putInt("night_mode", 1).apply()
                        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)}
                    else -> {
                        sharedPreferences.edit().putInt("night_mode", 2).apply()
                        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
                    }
                }
            }
            .setSingleChoiceItems(items, checkedItem) { dialog, which ->
                checkedItem = which
            }
            .setCancelable(false)
            .show()
    }

использовал кнопку для вызова themeDialog()

      findViewById<Button>(R.id.themeChangeBtn).setOnClickListener {
         themeDialog()
}
Другие вопросы по тегам