- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我已经在我的应用程序中成功实现了夜间模式,但只是当它 > 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/
我已经在我的应用程序中成功实现了夜间模式,但只是当它 > API29 (Android Q) 时。 在较旧的 API 中,我没有自动 DayNight 主题的功能(根据操作系统),因此我使用开关手动触
我在我的应用程序中实现了 DayNight 主题并添加了一个设置以在白天和夜间模式之间切换,但我无法在不重新启动的情况下动态切换模式。 如果我在更改设置后使用 setDefaultNightMode(
我正在使用 DayNight 主题和启动屏幕。 启动屏幕是一个白色背景的图层列表。 因此,当它出现时,白色 启动屏幕会显示,然后是白色 Activity 。但在晚上,白色 启动屏幕显示紧随其后的是黑暗
开始接触 Google 支持库的新更新,我想在我的应用中实现 Theme.AppCompat.DayNight。 我遇到的问题是似乎没有人解释如何定制它。所以,如果我想在白天使用不同的 colorAc
DayNight Theme 有四种情况: 设备 - 深色 模式,应用程序 - 深色 模式 设备 - 灯光 模式,应用程序 - 灯光 模式 设备 - 深色 模式,应用程序 - 灯光 模式 设备 - 灯
在我的 build.gradle 中,我包含了 Material 设计库(版本 1.1.0),但在 styles.xml 中, 当我尝试使用 Theme.MaterialComponents.DayN
我在我的应用中使用 MaterialComponents.DayNight 主题。在白天模式下,工具栏文本颜色为黑色。但是当我切换到夜间模式时,工具栏文本颜色保持黑色,所以它不再可见。 我想在夜间模
我读过这篇文章:https://medium.com/@chrisbanes/appcompat-v23-2-daynight-d10f90c83e94 .它提到了 DayNight 主题,然后: T
我正在将主题 Theme.AppCompat.DayNight.NoActionBar 应用于我的应用程序。 在浅色主题中,我希望状态栏为白色,而在深色主题中,我希望状态栏为黑色。 我不能让状态栏变成
我在我的布局中实现了一个切换按钮,并希望通过该按钮使用 Android dayNight 主题,dayNight 主题可以正常工作,但问题是每当我 单击开关它不会立即工作,我必须更改 Activity
我正在使用在 version 23.2 中引入的 AppCompat 的新 Theme.AppCompat.DayNight 主题,但它不会自动在白天(浅色)和夜晚(深色)主题之间切换,而是始终显示为
我正在创建一个应用程序,我在其中使用 Android 支持库的主题 DayNight。 这是themes.xml中的代码 @color/colorPrimary @color/col
在我的应用中,我尝试使用 uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_YES) 更改主题(浅色/深色)。 它在装有 Android 6 的
我为我的应用程序使用 Theme.AppCompat.DayNight.NoActionBar 主题。当我加载 adMob interstital 时,一些颜色在“夜间”模式下被破坏(即在 Recyc
我正在使用 Android 支持库 23.2 添加的新 Theme.AppCompat.DayNight 在 Android 5.1 上运行良好。 在 Android 6.0 上,Activity 看
我正在使用 MaterialDesign website 中描述的指南中的实现 无论我尝试什么,菜单文本颜色和 native 菜单图标(如展开菜单图标)都是错误的颜色,特别是它们似乎是浅色模式颜色。我
我有点困惑。我在我的应用中使用 DayNight 主题(使用 AppCompatDelegate.setDefaultNightMode()),但无法让它在我的 MainActivity 中工作。Ma
我已经下载了 Android Support 23.2.0 并在/Android/sdk/extras/android/support/samples/Support7Demos 目录下导入了 sup
我是一名优秀的程序员,十分优秀!