【问题标题】:How to avoid some custom views freezing the UI thread?如何避免一些自定义视图冻结 UI 线程?
【发布时间】:2015-12-11 13:06:32
【问题描述】:

我的一个游戏窗口中有 9 个自定义视图(每个都扩展了 View 类)导致我的 UI 线程冻结,当我按下“播放”按钮时,应用程序冻结(膨胀布局时)在“onCreateView”中,我使用 Fragments),直到生成游戏窗口,非常丑陋的东西。

我试图在一个单独的线程中执行此操作,但都是问题,Android 不允许我在主 (UI) 线程之外创建新视图。

我尝试了很多东西,但我无法做到,谁能告诉我如何做到这一点? 非常感谢

【问题讨论】:

    标签: android multithreading view main freeze


    【解决方案1】:

    对于 CPU 密集型绘图,您可以使用。

    http://developer.android.com/reference/android/view/SurfaceView.html

    这个类的一个目的是提供一个表面,其中一个 辅助线程可以渲染到屏幕中。

    【讨论】:

    • 谢谢Dominik,但问题不在游戏中。问题在于“播放窗口”和“游戏窗口”之间的转换,当我按下“播放”按钮时,应用程序在生成“游戏窗口”时冻结。加载“游戏窗口”时,所有工作都按预期进行。发生冻结是因为布局 xml 文件中有 9 个自定义视图。
    【解决方案2】:

    我通过手动填充 AsyncTask 中的布局解决了这个问题。我从显示“加载”视图的“播放窗口”调用 AsyncTask,在“onPostExecute”中创建“游戏窗口”(片段)并替换它。

    一些虚拟代码(PlayFragment 是 GameFragment 的前一屏):

    “播放按钮点击”(PlayFragment):

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_play:
                Bundle bundle = new Bundle();
                bundle.putSerializable(ARG_SELECTED_GAME, selectedGame);
                rlLoadingGame.setVisibility(View.VISIBLE);
                GameFragment gameFragment = GameFragment.newInstance(selectedGame);
                gameFragment.loadGame(activity, bundle);
                break;
        }
    }
    

    loadGame 方法(GameFragment):

    public void loadGame(Activity activity, Bundle bundle) {
        this.activity = activity;
        if (bundle != null) {
            currentGame = (Game) bundle.getSerializable(ARG_SELECTED_GAME);
        }
        new GenerateGame(bundle).execute();
    }
    

    GenerateGame AsyncTask (GameFragment):

    class GenerateGame extends AsyncTask<Void, Void>, View> {
        private Bundle bundle;
    
        public GenerateGame(Bundle bundle) {
            this.bundle = bundle;
        }
    
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // do your stuff
        }
    
        @Override
        protected View doInBackground(Void... params) {
            View child = activity.getLayoutInflater().inflate(R.layout.game_fragment_layout, null);
            // do all your heavy load stuff
            return child;
        }
    
        @Override
        protected void onPostExecute(View layout) {
            super.onPostExecute(layout);
            // initialize and set all UI elements
            replaceFragment(layout, bundle);
        }
    }
    

    replaceFragment 方法(GameFragment):

    private void replaceFragment(View newView, Bundle bundle) {
        fragmentLayout = newView;
        // call to fragment manager replace/add or required method passing this as Fragment to replace and the bundle if needed
    }
    

    onCreateView(游戏片段):

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (fragmentLayout != null) {
            return fragmentLayout;
        } else {
            return null;
        }
    }
    

    这是第一种方法,因此可以对其进行重构,并且可以以更好的方式完成很多事情,但这取决于您。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-27
      • 1970-01-01
      • 1970-01-01
      • 2019-09-04
      • 1970-01-01
      相关资源
      最近更新 更多