英文:
Android asks for not to query on main thread, but asyc queries are delaying
问题
正如标题所说,Android 需要在主线程之外执行查询,否则会抛出 java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time
错误。因此,我按照许多教程的解释,成功地实现了异步查询,但从目前来看,这并没有太多意义。
public class NewDetalleDiarioActivity extends AppCompatActivity {
@Override
protected void onStart() {
super.onStart();
db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database").build();
findPeriodo();
findDiario();
}
private void findPeriodo() {
periodo = Diarios.getPeriodo(db);
if (periodo == null) {
Intent intent = new Intent(NewDetalleDiarioActivity.this, NewPeriodoActivity.class);
startActivity(intent);
}
}
}
问题/错误:
如果 periodo
为空,会启动另一个活动,否则该活动将继续执行线程。
问题在于,当我调试它时(这会减慢进程,当然),periodo
会返回数据库中的实例,但当我不调试代码运行时,periodo
为空。
public class Diarios {
public static Periodo getPeriodo(AppDatabase db) {
return Factory.getIntPeriodo().getPeriodo(db);
}
}
public class Factory {
private static IntPeriodo intPeriodo;
public static IntPeriodo getIntPeriodo() {
return (intPeriodo == null) ? intPeriodo = new BusPeriodo() : intPeriodo;
}
}
public class BusPeriodo implements IntPeriodo {
// 我认为没有必要贴出接口部分...
@Override
public Periodo getPeriodo(final AppDatabase db) {
final Periodo[] periodo = new Periodo[1];
AsyncTask.execute(new Runnable() {
@Override
public void run() { // 那个让我发狂的异步查询。
periodo[0] = db.periodoDao().getPeriodo(new Date());
}
});
return periodo[0];
}
}
有没有正确的方法可以在不延迟查询的情况下执行 select
查询呢?
select
查询确实有效,我认为不需要贴出它(因为在 调试 时返回唯一结果),但是在没有调试的情况下运行代码时,它会返回 null!!请帮忙解决。
英文:
As the title says, android needs queries out of main thread since it will trhow java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time
otherwise. So I managed to make async queries as many tutorials explain, but it doesn't make so much sense (so far) as I could achieve.
public class NewDetalleDiarioActivity extends AppCompatActivity {
@Override
protected void onStart() {
super.onStart();
db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database").build();
findPeriodo();
findDiario();
}
private void findPeriodo() {
periodo = Diarios.getPeriodo(db);
if (periodo == null) {
Intent intent = new Intent(NewDetalleDiarioActivity.this, NewPeriodoActivity.class);
startActivity(intent);
}
}
PROBLEM/ERROR:
If periodo
is null, another activity is started, otherwise this one continues its thread.
The problem is that, when I debug it (which slows proceses, of course) periodo
returns an instance from the database, but when I run the code without debugging, periodo
is null.
public class Diarios {
public static Periodo getPeriodo(AppDatabase db) {
return Factory.getIntPeriodo().getPeriodo(db);
}
}
.
public class Factory {
private static IntPeriodo intPeriodo;
public static IntPeriodo getIntPeriodo() {
return (intPeriodo == null) ? intPeriodo = new BusPeriodo() : intPeriodo;
}
}
.
public class BusPeriodo implements IntPeriodo {
// I don't think it's necessary to post the interface...
@Override
public Periodo getPeriodo(final AppDatabase db) {
final Periodo[] periodo = new Periodo[1];
AsyncTask.execute(new Runnable() {
@Override
public void run() { //the async query that is driving me mad.
periodo[0] = db.periodoDao().getPeriodo(new Date());
}
});
return periodo[0];
}
}
What's the proper way to make select
queries without getting them delayed?
The select query
is indeed working, I don't think is necessary to post it (because it is returning an unique result when I debug), but it returns null when I run the code without debugging!! Please help.
答案1
得分: 0
SOLUTION:
正如 @user7041125 所建议的,但我创建了一个新的类,使用接口将方法回调到活动中,就像这样:
public class PeriodoBridge extends AsyncTask<Void, Void, Periodo> implements IntPeriodoBridge {
private WeakReference<Activity> weakActivity;
private IntPeriodoBridge caller; //在需要查询的活动中实现这个接口
private AppDatabase db;
private Periodo periodo;
public PeriodoBridge(Activity activity, IntPeriodoBridge caller, AppDatabase db) {
weakActivity = new WeakReference<>(activity);
this.caller = caller; //将活动实例分配给本地接口实例
this.db = db;
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@Override
protected Periodo doInBackground(Void... voids) {
periodo = Diarios.getPeriodo(db);
return periodo;
}
@Override
protected void onPostExecute(Periodo periodo) {
Activity activity = weakActivity.get();
if (activity == null) {
return;
}
if (periodo == null) {
Intent intent = new Intent(activity, NewPeriodoActivity.class);
activity.startActivity(intent);
} else {
setPeriodo(periodo);
}
}
@Override //这是一个接口方法(IntPeriodoBridge)
public void setPeriodo(Periodo periodo) {
caller.setPeriodo(periodo); //我可以通过这个方法将查询结果返回给活动类
}
}
调用这个类的 init 方法。活动实现了 `IntPeriodoBridge`,这样我就可以将查询结果对象设置到活动类中。
英文:
SOLUTION:
As @user7041125 suggested, but instead I made a new class with an interface to call methods back to the activity, like this:
public class PeriodoBridge extends AsyncTask<Void, Void, Periodo> implements IntPeriodoBridge {
private WeakReference<Activity> weakActivity;
private IntPeriodoBridge caller; //implement this interface in the activity which needs to query
private AppDatabase db;
private Periodo periodo;
public PeriodoBridge(Activity activity, IntPeriodoBridge caller, AppDatabase db) {
weakActivity = new WeakReference<>(activity);
this.caller = caller; // assign activity instance to the local interface instance
this.db = db;
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@Override
protected Periodo doInBackground(Void... voids) {
periodo = Diarios.getPeriodo(db);
return periodo;
}
@Override
protected void onPostExecute(Periodo periodo) {
Activity activity = weakActivity.get();
if (activity == null) {
return;
}
if (periodo == null) {
Intent intent = new Intent(activity, NewPeriodoActivity.class);
activity.startActivity(intent);
} else {
setPeriodo(periodo);
}
}
@Override //this is an interface method (IntPeriodoBridge)
public void setPeriodo(Periodo periodo) {
caller.setPeriodo(periodo); //I can set the query result back to the activity class with this
}
Call the init method of this class. The activity implements IntPeriodoBridge
and in that way I can set the query result object to the activity class.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论