Android asynctask doinbackground行为在Android7中发生了变化



我的应用具有带有异步的片段,该片段从数据库中获取记录,并使用listView显示它们。已经运行良好了几年,但是现在在Android 7 IT停滞不前,没有显示记录。但是,离开应用程序(例如进入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立即执行: - 触摸最近的按钮 - 按主键 - 向下滚动并选择设置图标

看来,审计范围的生命周期状态或其父活动的变化正在解除执行Doinbackground。

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

实验: -RESTORE UPDATAUDITTASK.EXECUTEONEXECUTOR(asynctask.thread_pool_executor((而不是使用我自己的执行程序( 在调用executeOneXecutor

之前
  1. Android 7. Stalls,即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
    

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

实验2。禁用较早开始的一个异步。这次,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,因此单个长期运行的任务将阻止任何其他任务运行。我通过查看棉花糖AsyncTask来源发现了这一点,并在我的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具有公共静态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阻止串行executor。

这些是在Android 7中改变AsyncTask的提交。我看不到吸烟枪。

  • 调整asynctask#thread_pool_executor设置
  • 更多修复问题#22765972:粘合剂交易用尽了地址空间,导致软件包管理器失败
  • 修复异步箱以处理Doinbackground中的异常
  • 异步终止的异常呼叫oncancelded

我在正在处理的应用程序上遇到了同样的问题。这真的很奇怪,因为相同的代码在其他一些设备上使用相同的版本,配置...但是,解决方法可以帮助您:使用 rx 代替异步。我无法解释主要原因,但它解决了我的阻塞问题。

相关内容

最新更新