Android要求不要在主线程上查询,但是异步查询正在延迟执行。

huangapple 未分类评论54阅读模式
英文:

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 错误。因此,我按照许多教程的解释,成功地实现了异步查询,但从目前来看,这并没有太多意义。

  1. public class NewDetalleDiarioActivity extends AppCompatActivity {
  2. @Override
  3. protected void onStart() {
  4. super.onStart();
  5. db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database").build();
  6. findPeriodo();
  7. findDiario();
  8. }
  9. private void findPeriodo() {
  10. periodo = Diarios.getPeriodo(db);
  11. if (periodo == null) {
  12. Intent intent = new Intent(NewDetalleDiarioActivity.this, NewPeriodoActivity.class);
  13. startActivity(intent);
  14. }
  15. }
  16. }

问题/错误:

如果 periodo 为空,会启动另一个活动,否则该活动将继续执行线程。
问题在于,当我调试它时(这会减慢进程,当然),periodo 会返回数据库中的实例,但当我不调试代码运行时,periodo 为空。

  1. public class Diarios {
  2. public static Periodo getPeriodo(AppDatabase db) {
  3. return Factory.getIntPeriodo().getPeriodo(db);
  4. }
  5. }
  6. public class Factory {
  7. private static IntPeriodo intPeriodo;
  8. public static IntPeriodo getIntPeriodo() {
  9. return (intPeriodo == null) ? intPeriodo = new BusPeriodo() : intPeriodo;
  10. }
  11. }
  12. public class BusPeriodo implements IntPeriodo {
  13. // 我认为没有必要贴出接口部分...
  14. @Override
  15. public Periodo getPeriodo(final AppDatabase db) {
  16. final Periodo[] periodo = new Periodo[1];
  17. AsyncTask.execute(new Runnable() {
  18. @Override
  19. public void run() { // 那个让我发狂的异步查询。
  20. periodo[0] = db.periodoDao().getPeriodo(new Date());
  21. }
  22. });
  23. return periodo[0];
  24. }
  25. }

有没有正确的方法可以在不延迟查询的情况下执行 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.

  1. public class NewDetalleDiarioActivity extends AppCompatActivity {
  2. @Override
  3. protected void onStart() {
  4. super.onStart();
  5. db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database").build();
  6. findPeriodo();
  7. findDiario();
  8. }
  9. private void findPeriodo() {
  10. periodo = Diarios.getPeriodo(db);
  11. if (periodo == null) {
  12. Intent intent = new Intent(NewDetalleDiarioActivity.this, NewPeriodoActivity.class);
  13. startActivity(intent);
  14. }
  15. }

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.

  1. public class Diarios {
  2. public static Periodo getPeriodo(AppDatabase db) {
  3. return Factory.getIntPeriodo().getPeriodo(db);
  4. }
  5. }

.

  1. public class Factory {
  2. private static IntPeriodo intPeriodo;
  3. public static IntPeriodo getIntPeriodo() {
  4. return (intPeriodo == null) ? intPeriodo = new BusPeriodo() : intPeriodo;
  5. }
  6. }

.

  1. public class BusPeriodo implements IntPeriodo {
  2. // I don't think it's necessary to post the interface...
  3. @Override
  4. public Periodo getPeriodo(final AppDatabase db) {
  5. final Periodo[] periodo = new Periodo[1];
  6. AsyncTask.execute(new Runnable() {
  7. @Override
  8. public void run() { //the async query that is driving me mad.
  9. periodo[0] = db.periodoDao().getPeriodo(new Date());
  10. }
  11. });
  12. return periodo[0];
  13. }
  14. }

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 所建议的,但我创建了一个新的类,使用接口将方法回调到活动中,就像这样:

  1. public class PeriodoBridge extends AsyncTask<Void, Void, Periodo> implements IntPeriodoBridge {
  2. private WeakReference<Activity> weakActivity;
  3. private IntPeriodoBridge caller; //在需要查询的活动中实现这个接口
  4. private AppDatabase db;
  5. private Periodo periodo;
  6. public PeriodoBridge(Activity activity, IntPeriodoBridge caller, AppDatabase db) {
  7. weakActivity = new WeakReference<>(activity);
  8. this.caller = caller; //将活动实例分配给本地接口实例
  9. this.db = db;
  10. executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  11. }
  12. @Override
  13. protected Periodo doInBackground(Void... voids) {
  14. periodo = Diarios.getPeriodo(db);
  15. return periodo;
  16. }
  17. @Override
  18. protected void onPostExecute(Periodo periodo) {
  19. Activity activity = weakActivity.get();
  20. if (activity == null) {
  21. return;
  22. }
  23. if (periodo == null) {
  24. Intent intent = new Intent(activity, NewPeriodoActivity.class);
  25. activity.startActivity(intent);
  26. } else {
  27. setPeriodo(periodo);
  28. }
  29. }
  30. @Override //这是一个接口方法(IntPeriodoBridge)
  31. public void setPeriodo(Periodo periodo) {
  32. caller.setPeriodo(periodo); //我可以通过这个方法将查询结果返回给活动类
  33. }
  34. }
  35. 调用这个类的 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:

  1. public class PeriodoBridge extends AsyncTask&lt;Void, Void, Periodo&gt; implements IntPeriodoBridge {
  2. private WeakReference&lt;Activity&gt; weakActivity;
  3. private IntPeriodoBridge caller; //implement this interface in the activity which needs to query
  4. private AppDatabase db;
  5. private Periodo periodo;
  6. public PeriodoBridge(Activity activity, IntPeriodoBridge caller, AppDatabase db) {
  7. weakActivity = new WeakReference&lt;&gt;(activity);
  8. this.caller = caller; // assign activity instance to the local interface instance
  9. this.db = db;
  10. executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  11. }
  12. @Override
  13. protected Periodo doInBackground(Void... voids) {
  14. periodo = Diarios.getPeriodo(db);
  15. return periodo;
  16. }
  17. @Override
  18. protected void onPostExecute(Periodo periodo) {
  19. Activity activity = weakActivity.get();
  20. if (activity == null) {
  21. return;
  22. }
  23. if (periodo == null) {
  24. Intent intent = new Intent(activity, NewPeriodoActivity.class);
  25. activity.startActivity(intent);
  26. } else {
  27. setPeriodo(periodo);
  28. }
  29. }
  30. @Override //this is an interface method (IntPeriodoBridge)
  31. public void setPeriodo(Periodo periodo) {
  32. caller.setPeriodo(periodo); //I can set the query result back to the activity class with this
  33. }

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.

huangapple
  • 本文由 发表于 2020年5月2日 12:35:45
  • 转载请务必保留本文链接:https://java.coder-hub.com/61554518.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定