gpt4 book ai didi

Android AsyncTask doInBackground 行为在 Android7 中发生了变化

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:30:46 26 4
gpt4 key购买 nike

我的应用程序有一个带有 AsyncTask 的 Fragment,它从数据库中获取记录并使用 ListView 显示它们。几年来一直运行良好,但现在在 Android 7 上它停止了,没有显示任何记录。但是,在离开应用程序(例如进入 Android 设置)然后返回时,会显示记录。调试发现一开始执行了onPreExecute,doInBackground直到离开应用的那一刻才执行。

谁能提出 Android 7 中的哪些变化可以解释这一点?

        // 1. ==== Fragment containing AsyncTask ====

public class AuditFragment extends ListFragment implements OnClickListener
{

// Using beep for debugging until I can get LogCat in Eclipse restored for Android 7
public static void beep ( final int times )
{
...
}

private class UpdateAuditTask extends AsyncTask<Void, RecordEntry, SQLException>
{

@Override
protected SQLException doInBackground ( Void... parameters )
{
beep ( 5 ); // Debug, in the absence of LogCat
...
}

@Override
protected void onProgressUpdate ( RecordEntry... values )
{
L.logMethodCall ( (Object[]) values );

if ( values.length == 1 )
{
auditListAdapter.add ( values[0] );
auditListAdapter.notifyDataSetChanged ();
}
}

@Override
protected void onPreExecute ()
{
L.logMethodCall ();
beep ( 2 ); // Debug, in the absence of LogCat
auditListAdapter.clear ();
}

@Override
protected void onPostExecute ( SQLException result )
{
L.logMethodCall ( result );
...
}
}

private void updateAuditList ()
{
L.logMethodCall ();

beep (1); // Debug, in the absence of LogCat

new UpdateAuditTask ().execute ();
auditListAdapter.notifyDataSetChanged ();
}

public AuditFragment()
{
}

@Override
public void onClick ( View view )
{
...
}

@Override
public View onCreateView ( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState )
{
...
}

@Override
public void onStart ()
{
L.logMethodCall ();
super.onStart ();

getListView ().setAdapter ( auditListAdapter );
updateFragmentGui ();
}

@Override
public void onResume ()
{
L.logMethodCall ();
super.onResume ();
...
}

private void updateFragmentGui ()
{
L.logMethodCall ();
...
}

private class AuditListAdapter extends ArrayAdapter<RecordEntry>
{
...
}

}

// 2. ==== Activity which executes Fragment ====

public class AuditActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
L.logMethodCall(savedInstanceState);
setContentView(R.layout.audit);

// Add "static" fragments
if (savedInstanceState == null) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
AuditFragment audit = new AuditFragment();
ft.add(R.id.kstation_audit_audit_frag, audit);
ft.commit();
}
}

@Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.donothing, R.anim.collapse_righttoleft);
}
}

// 3. ==== Method in main Activity ====

public void showAudit() {
Intent intent = new Intent(C.getActivity(), AuditActivity.class);
C.getActivity().startActivity(intent);
}

我正在三星 SM-T580 上进行测试。
当应用程序在 onPreExecute 运行后“停止”时,以下任何操作都会导致 doInBackground 立即执行:- 触摸最近按钮- 按主页键- 向下滚动并选择“设置”图标

AuditFragment 或其父 Activity 的生命周期状态的变化似乎正在取消阻止 doInBackground 的执行。

更新:我已经设法恢复了 Android 7 的 LogCat 可见性(使用 sdk 工具 Monitor 而不是 Eclipse),因此获得了一些调试信息。

实验: - 恢复 updateAuditTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)(而不是使用我自己的执行器) 并在调用 executeOnExecutor 之前将 THREAD_POOL_EXECUTOR 属性输出到 LogCat

  1. Android 7. 停顿,即 doInBackground 不执行。

            THREAD_POOL_EXECUTOR.getCorePoolSize ()  : 4
    THREAD_POOL_EXECUTOR.getMaximumPoolSize(): 17
    THREAD_POOL_EXECUTOR.getPoolSize() : 4
    THREAD_POOL_EXECUTOR.getActiveCount() : 4
  2. Android 6。不会停止,即 doInBackground 会执行。

            THREAD_POOL_EXECUTOR.getCorePoolSize ()  : 5
    THREAD_POOL_EXECUTOR.getMaximumPoolSize(): 9
    THREAD_POOL_EXECUTOR.getPoolSize() : 5
    THREAD_POOL_EXECUTOR.getActiveCount() : 5

我对此感到困惑:在每种情况下,当前 Activity 的线程都不少于核心池大小;新任务在 Android6 中运行,但在 Android7 中不运行。

实验 2。禁用一个较早启动的 AsyncTask。这一次,THREAD_POOL_EXECUTOR 属性与以前相同,但任务不会停止。

  1. Android 7。不会停止,即 doInBackground 会执行。

            THREAD_POOL_EXECUTOR.getCorePoolSize ()  : 4
    THREAD_POOL_EXECUTOR.getMaximumPoolSize(): 17
    THREAD_POOL_EXECUTOR.getPoolSize() : 4
    THREAD_POOL_EXECUTOR.getActiveCount() : 4

所以池大小等似乎与任务是否执行无关?

(澄清。早些时候,我错误地报告说我曾在禁用早期任务的情况下尝试过它;我反而禁用了一些在单独线程上运行的任务。)

最佳答案

默认情况下,AsyncTask.execute() 使用AsyncTask.SERIAL_EXECUTOR,因此单个长时间运行的任务将阻止任何其他任务运行。我通过查看 Marshmallow AsyncTask source 发现了这一点并在我的 6.0.1 设备上对其进行了验证。

new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(final Void... voids) {
Log.d("DERP", "bad task starting");
try {
Thread.sleep(5000);
}
catch(InterruptedException e) {
// ignore
}
finally {
Log.d("DERP", "bad task exiting");
}
return null;
}
}.execute();

new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(final Void... voids) {
Log.d("DERP", "nice task running");
return null;
};
}.execute();

输出:

06-30 15:43:23.777 8761-8792/com.chalcodes.rogueasynctask D/DERP: bad task starting
06-30 15:43:28.777 8761-8792/com.chalcodes.rogueasynctask D/DERP: bad task exiting
06-30 15:43:28.779 8761-9084/com.chalcodes.rogueasynctask D/DERP: nice task running

我建议使用 executeOnExecutor(...) 并提供您自己的执行器。如果您无法控制的两个任务相互干扰,您可以使用此 hack 来更改默认执行程序。 AsyncTask 有一个 public static setDefaultExecutor 方法,但是它被标记为 @hide 所以你必须通过反射访问它。

try {
final Method method = AsyncTask.class.getMethod("setDefaultExecutor", Executor.class);
method.invoke(null, executor);
} catch(Exception e) {
Log.e("AsyncTask", "error setting default executor", e);
}

但这并不能解释 Android 6 和 7 之间发生了什么变化。可能与 AsyncTask 无关的变化导致一个 AsyncTask 阻塞串行执行器。

这些是在 Android 7 中更改 AsyncTask 的提交。我没有看到确凿的证据。

关于Android AsyncTask doInBackground 行为在 Android7 中发生了变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44785695/

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