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

huangapple go评论89阅读模式
英文:

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&lt;Void, Void, Periodo&gt; implements IntPeriodoBridge {

    private WeakReference&lt;Activity&gt; 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&lt;&gt;(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.

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

发表评论

匿名网友

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

确定