gpt4 book ai didi

java - 如何手动更改 DayNight 主题?

转载 作者:太空宇宙 更新时间:2023-11-04 09:04:30 29 4
gpt4 key购买 nike

我已经在我的应用程序中成功实现了夜间模式,但只是当它 > API29 (Android Q) 时。
在较旧的 API 中,我没有自动 DayNight 主题的功能(根据操作系统),因此我使用开关手动触发主题,然后将主题保存在首选项中,以便当用户再次启动 Activity 时加载主题。这是开关代码(此代码位于 fragment 内):

DarkSwitch.setOnCheckedChangeListener((compoundButton, b) -> {
if (b) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
p.setBoolean("NightMode", true); //P is an instance of a class I have called PrefUtils that saves the user preferences
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
p.setBoolean("NightMode", false);
}
((MainActivity) getActivity()).recreate();
});

上面的代码工作正常,它以所需的主题重新启动 Activity 并将 boolean 值保存在首选项中。但是,主要问题是当我重新启动应用程序时。 Activity 在 setContentView() 之前更改主题,并加载主题,但在尝试从 AsyncTask 访问我的数据库后,它抛出异常:

java.lang.RuntimeException: An error occured while executing doInBackground() Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.sqlite.SQLiteDatabase android.content.Context.openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase$CursorFactory, android.database.DatabaseErrorHandler)' on a null object reference

我的猜测是,以某种方式更改主题可能会导致上下文为空,并且此空上下文被传递给 fragment ,与尝试通过 AsyncTask 访问数据库的 fragment 相同,并且它会引发异常。
这很奇怪,因为应用程序仅在加载 Activity 时崩溃(它不会在第一个代码 fragment 中崩溃),并且仅在 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); 时崩溃。被执行,只有当用户将首选项“NightMode”设置为 true 时才会发生这种情况。

这是我的 Activity 代码:

private void initTheme() {
PrefUtils p = new PrefUtils(this);
if (p.getBoolean("NightMode", false) || AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
getDelegate().applyDayNight();
}
}

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

编辑
我通过我的FolderFragment访问数据库值,该值与附加到initFragments()中的 Activity 相同:

public Fragment fragment1 = new FolderFragment();
private void initFragments()
{
fm.beginTransaction().add(R.id.fragmentcontainer, fragment1, "1").commit();
}

这是我的FolderFragment的代码:

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.folderfragment, container, false);
new RefreshData(v).execute();


return v;
}

private class RefreshData extends AsyncTask<Void, Void, Void> {

private View v;
private String title;
private Drawable drawable;

public RefreshData(View v) {
this.v = v;
}

@Override
protected void onPreExecute() {
super.onPreExecute();
Progress = v.findViewById(R.id.FFProgress); //Progress is my ProgressBar
Progress.setVisibility(View.VISIBLE);
}

@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
PAdapter = new ListAdapter(mList, getContext(), Mode);
Pager.setAdapter(PAdapter);
Progress.setVisibility(View.GONE); //Hides the ProgressBar because has finished
}

@Override
protected Void doInBackground(Void... voids) {
mList = getLists();
return null;
}

private void getLists()
{
ArrayList<ListItem> l = new ArrayList<>();
DatabaseHelper d = new DatabaseHelper(getContext());

Cursor res = d.getAllLists();

try
{
while (res.moveToNext()) {
int ID = res.getInt(0);
int FolderID = res.getInt(1);
String Title = res.getString(2);
String Description = res.getString(3);
String ColorHex = res.getString(4);
int Tag = res.getInt(5);

l.add(new ListItem(ID, FolderID, Title, Description, ColorHex, Tag));
}
}
catch(Exception ignored)
{

}
return l;
}

}

该类"DatabaseHelper"是管理所有 select 和 insert 语句的一个:

public class DatabaseHelper extends SQLiteOpenHelper{
public Cursor getAllLists() {
try
{
SQLiteDatabase db = this.getWritableDatabase(); //This is where throws the exception
return db.rawQuery(Db.Query.SELECT_LISTS, null);
}
catch(Exception e)
{

}
return null;
}

}

最佳答案

View 未附加到 onCreateView 内的 Activity/Fragment (这就是通货膨胀中的 false 也在说的。 false 意味着不要附加,因为当您从该方法返回 View 时,系统将附加它)。

开始操作 View 并执行此时使用 View 和上下文的任务本身是危险的。

我会搬家new RefreshData(v).execute();进入onActivityCreated .

<小时/>

但是你的问题是你的 ASyncTask 是非静态的,这就是为什么你可以使用 getContext()里面的方法。因此,问题要么是任务持有旧引用并且它正在变为空,要么是它在生命周期中过早地请求引用并且其为空。

我认为上述修复移至 onActivityCreated可能会修复它,但它仍然不是最好的。

然后我将更改您的 ASyncTask 以使其静态:

private static class RefreshData extends AsyncTask<Void, Void, Void> {

然后更改您使用的任何位置 getContext()v.getContext()

new DatabaseHelper(getContext());

变成了

new DatabaseHelper(v.getContext());

您还可以显式传递上下文,就像传递 View 的方式一样。那就更好了。实际上最好的办法是这样做:

@Override
public void onActivityCreated (Bundle savedInstanceState) {
DatabaseHelper dbHelper = new DatabaseHelper(getContext());
ProgressBar progressView = findViewById(R.id.FFProgress);
new RefreshData(dbHelper, progressView).execute();
}

private static class RefreshData extends AsyncTask<Void, Void, Void> {

private final View progress;
private final DatabaseHelper dbHelper;
private String title;
private Drawable drawable;

public RefreshData(DatabaseHelper dbHelper, View progress) {
this.dbHelper = dbHelper;
this.progress = progress;
}

等等..以便您明确声明任务使用什么,并从 Activity 中传递它们。

<小时/>

旁注:

你有很多以大写字符开头的变量,例如:

String Title = res.getString(2);

您应该避免这样做,以免让自己感到困惑。 java开发者的惯用约定是使用大写字符来命名类,例如 DatabaseHelper以及小写变量,例如 title 。然后再驼峰式地表达任何进一步的话。所以这就变成了:

String title = res.getString(2);

关于java - 如何手动更改 DayNight 主题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60384284/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com