简体   繁体   English

在android中非常缓慢的布局膨胀

[英]Extremely slow layout inflating in android

I'm refactoring android application.我正在重构 android 应用程序。 Before first start I've made quite a lot of changes and at some step it became sluggish in some places.在第一次开始之前,我做了很多改变,在某些地方它变得迟钝。 Here's one of such places.这里是这样的地方之一。

I have a tab layout with several Fragments.我有一个包含多个 Fragment 的选项卡布局。 Some Fragments work fine, but this one is sluggish.一些 Fragments 工作正常,但这个是缓慢的。 It simply takes some "Brands" from android room database and fills ListView by using Adapter.它只是从 android 房间数据库中获取一些“品牌”并使用 Adapter 填充 ListView。

Fragment onCreateView method :片段 onCreateView 方法:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_item_list_ll, container, false);
        LinearLayout linearLayout = view.findViewById(R.id.fragment_layout);
        mListView = linearLayout.findViewById(android.R.id.list);
        mListView.setAdapter(mAdapter);
        mListView.setOnItemClickListener((adapterView, view1, i, l) -> {
            Brand brand = mAdapter.getItem(i);
            if(brand == null) return;
            brand.setSelected(!brand.isSelected());
            mBrandsViewModel.upsertBrand(brand);
        });
        return view;
    }

Adapter getView:适配器获取视图:

    @Override
    public View getView(final int position, View convertView, @NonNull ViewGroup parent) {
        Logger.i(getClass().getName(), "Called getView");
        if (convertView == null) {
            LayoutInflater inflater = context.getLayoutInflater();
            Logger.i(getClass().getName(), "Got inflater");
            convertView = inflater.inflate(R.layout.brand_list_item, parent, false);
        }
        Logger.i(getClass().getName(), "View inflated");
        TextView brandNameTextView = convertView.findViewById(R.id.brandNameTextView);
        CheckBox brandCheckBox = convertView.findViewById(R.id.brandCheckBox);
        Brand brand = brands.get(position);
        brandNameTextView.setText(brand.getBrandName());
        brandCheckBox.setChecked(brand.isSelected());
        brandNameTextView.setGravity(Gravity.CENTER);
        return convertView;

//        if (convertView == null) {
//            LayoutInflater inflater = context.getLayoutInflater();
//            convertView = inflater.inflate(android.R.layout.simple_list_item_checked, null, true);
//
//        }
//        Brand brand = brands.get(position);
//        CheckedTextView textView = convertView.findViewById(android.R.id.text1);
//        textView.setText(brand.getBrandName());
//        textView.setChecked(brand.isSelected());
//        return convertView;
    }

XML of R.layout.brand_list_item R.layout.brand_list_item 的 XML

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="blocksDescendants"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:baselineAligned="false"
        android:orientation="horizontal"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:weightSum="1">

        <TextView
            android:id="@+id/brandNameTextView"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <CheckBox
            android:id="@+id/brandCheckBox"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_weight="1" />
    </LinearLayout>
</LinearLayout>

And here's logcat when the Fragment is being created这是创建 Fragment 时的 logcat

03-17 07:25:55.249 4181-4181/some.package.here D/AbsListView: onDetachedFromWindow
03-17 07:25:55.309 4181-4181/some.package.here D/AbsListView: Get MotionRecognitionManager
03-17 07:25:55.449 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Called getView
03-17 07:25:55.449 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Got inflater
03-17 07:25:55.729 4181-4181/some.package.here D/dalvikvm: GC_FOR_ALLOC freed 1461K, 33% free 9585K/14264K, paused 36ms, total 36ms
03-17 07:25:56.359 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:25:56.909 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:25:56.919 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: View inflated
03-17 07:25:56.979 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Called getView
03-17 07:25:56.979 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Got inflater
03-17 07:25:57.749 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:25:58.289 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:25:58.299 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: View inflated
03-17 07:25:58.359 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Called getView
03-17 07:25:58.359 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Got inflater
03-17 07:25:58.979 4181-4181/some.package.here D/dalvikvm: GC_FOR_ALLOC freed 3488K, 43% free 8144K/14264K, paused 34ms, total 34ms
03-17 07:25:59.119 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:25:59.659 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:25:59.669 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: View inflated
03-17 07:25:59.739 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Called getView
03-17 07:25:59.739 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Got inflater
03-17 07:26:00.499 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:26:01.049 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:26:01.059 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: View inflated
03-17 07:26:01.089 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Called getView
03-17 07:26:01.089 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Got inflater
03-17 07:26:01.669 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:26:02.079 4181-4181/some.package.here D/dalvikvm: GC_FOR_ALLOC freed 1523K, 40% free 8669K/14264K, paused 33ms, total 33ms
03-17 07:26:02.399 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:26:02.419 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: View inflated
03-17 07:26:02.479 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Called getView
03-17 07:26:02.479 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Got inflater
03-17 07:26:03.239 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:26:03.789 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:26:03.799 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: View inflated
03-17 07:26:03.869 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Called getView
03-17 07:26:03.869 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Got inflater
03-17 07:26:04.449 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:26:05.039 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:26:05.059 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: View inflated
03-17 07:26:05.099 4181-4181/some.package.here D/dalvikvm: GC_FOR_ALLOC freed 1536K, 36% free 9142K/14264K, paused 35ms, total 35ms
03-17 07:26:05.239 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Called getView
03-17 07:26:05.239 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: Got inflater
03-17 07:26:06.019 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:26:06.559 4181-4181/some.package.here W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-17 07:26:06.569 4181-4181/some.package.here I/some.package.here.preference.adapters.BrandAdapter: View inflated
03-17 07:26:06.679 4181-4181/some.package.here I/Choreographer: Skipped 679 frames!  The application may be doing too much work on its main thread.

I've noticed that something happens during inflation, but I can't figure out what exactly and how to solve sluggish performance.我注意到在通货膨胀期间会发生一些事情,但我无法弄清楚究竟是什么以及如何解决缓慢的性能。 Also I don't understand why res/layout/dialog_title_holo.xml is being called.另外我不明白为什么res/layout/dialog_title_holo.xml被调用。

Important things to know:需要了解的重要事项:

  • every sluggish place in the app has W/Resources: Converting to boolean: TypedValue...应用程序中每个缓慢的地方都有W/Resources: Converting to boolean: TypedValue...
  • when I use built-in item android.R.layout.simple_list_item_checked instead of my own in adapter's getView method (commented out part) then everything works like a charm.当我在适配器的 getView 方法(注释掉的部分)中使用内置项目android.R.layout.simple_list_item_checked而不是我自己的项目时,一切都像魅力一样。

Edit: ViewHolder pattern doesn't solve the problem.编辑: ViewHolder 模式不能解决问题。 I'm observing the same message in logcat: W/Resources: Converting to boolean: TypedValue... Appreciate any help.我在 logcat 中观察到相同的消息: W/Resources: Converting to boolean: TypedValue...感谢任何帮助。

The problem with your code is you are initialising view for each list item.您的代码的问题是您正在为每个列表项初始化视图。 You can either replace listview with recycler view else use view holder in you list adapter.您可以使用回收器视图替换列表视图,也可以在列表适配器中使用视图持有者。

@Override
public View getView(final int position, View convertView, @NonNull ViewGroup parent) {
    ViewHolder viewHolder;

    if (convertView == null) {
            LayoutInflater inflater = context.getLayoutInflater();
            Logger.i(getClass().getName(), "Got inflater");
            convertView = inflater.inflate(R.layout.brand_list_item, parent, false);
            viewHolder = new ViewHolder(convertView);
            convertView.setTag(viewHolder);
    }else{
        viewHolder = (ViewHolder) convertView.getTag();
    }

    Brand brand = brands.get(position);
    viewHolder.brandNameTextView.setText(brand.getBrandName());
    viewHolder.brandCheckBox.setChecked(brand.isSelected());
    viewHolder.brandNameTextView.setGravity(Gravity.CENTER);
    return convertView;
}

public static class ViewHolder{
    public TextView brandNameTextView;
    public CheckBox brandCheckBox;

    public ViewHolder(View view){
        brandNameTextView = view.findViewById(R.id.brandNameTextView);
        brandCheckBox = view.findViewById(R.id.brandCheckBox);
    }
}

Okay.好的。 I think I found the reason.我想我找到了原因。

During refactoring I moved the app from android.support libs to androidx lib, which is apparently not friendly to old platform devices (mine is quite old)在重构期间,我将应用程序从 android.support libs 移到了 androidx lib,这显然对旧平台设备不友好(我的已经很旧了)

How I came to this conclusion:我是如何得出这个结论的:

  1. Took demo-project from this article (which uses android.support libs)从接过演示项目文章(使用android.support库)
  2. Compiled, ran, everything works fine编译,运行,一切正常
  3. Changed gradle from android.support to androidx and voi là:将 gradle 从 android.support 更改为 androidx 和 voi là:
03-18 07:34:48.789 20235-20235/de.jakobulbrich.preferences D/dalvikvm: VFY: replacing opcode 0x1f at 0x0006
03-18 07:34:49.359 20235-20235/de.jakobulbrich.preferences W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-18 07:34:49.899 20235-20235/de.jakobulbrich.preferences W/Resources: Converting to boolean: TypedValue{t=0x3/d=0x4e4 "res/layout/dialog_title_holo.xml" a=2 r=0x109004d}
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences I/dalvikvm: Could not find method android.widget.CompoundButton.getButtonDrawable, referenced from method androidx.core.widget.CompoundButtonCompat.getButtonDrawable
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences W/dalvikvm: VFY: unable to resolve virtual method 2762: Landroid/widget/CompoundButton;.getButtonDrawable ()Landroid/graphics/drawable/Drawable;
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences D/dalvikvm: VFY: replacing opcode 0x6e at 0x0006
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences I/dalvikvm: Could not find method android.widget.CompoundButton.getButtonTintList, referenced from method androidx.core.widget.CompoundButtonCompat.getButtonTintList
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences W/dalvikvm: VFY: unable to resolve virtual method 2763: Landroid/widget/CompoundButton;.getButtonTintList ()Landroid/content/res/ColorStateList;
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences D/dalvikvm: VFY: replacing opcode 0x6e at 0x0006
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences I/dalvikvm: Could not find method android.widget.CompoundButton.getButtonTintMode, referenced from method androidx.core.widget.CompoundButtonCompat.getButtonTintMode
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences W/dalvikvm: VFY: unable to resolve virtual method 2764: Landroid/widget/CompoundButton;.getButtonTintMode ()Landroid/graphics/PorterDuff$Mode;
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences D/dalvikvm: VFY: replacing opcode 0x6e at 0x0006
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences I/dalvikvm: Could not find method android.widget.CompoundButton.setButtonTintList, referenced from method androidx.core.widget.CompoundButtonCompat.setButtonTintList
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences W/dalvikvm: VFY: unable to resolve virtual method 2780: Landroid/widget/CompoundButton;.setButtonTintList (Landroid/content/res/ColorStateList;)V
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences D/dalvikvm: VFY: replacing opcode 0x6e at 0x0006
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences I/dalvikvm: Could not find method android.widget.CompoundButton.setButtonTintMode, referenced from method androidx.core.widget.CompoundButtonCompat.setButtonTintMode
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences W/dalvikvm: VFY: unable to resolve virtual method 2781: Landroid/widget/CompoundButton;.setButtonTintMode (Landroid/graphics/PorterDuff$Mode;)V
03-18 07:34:49.909 20235-20235/de.jakobulbrich.preferences D/dalvikvm: VFY: replacing opcode 0x6e at 0x0006
03-18 07:34:50.209 20235-20235/de.jakobulbrich.preferences I/dalvikvm: Could not find method android.view.View.setTooltipText, referenced from method androidx.appcompat.widget.TooltipCompat.setTooltipText
03-18 07:34:50.209 20235-20235/de.jakobulbrich.preferences W/dalvikvm: VFY: unable to resolve virtual method 2127: Landroid/view/View;.setTooltipText (Ljava/lang/CharSequence;)V
03-18 07:34:50.209 20235-20235/de.jakobulbrich.preferences D/dalvikvm: VFY: replacing opcode 0x6e at 0x0006
03-18 07:34:50.219 20235-20235/de.jakobulbrich.preferences I/Choreographer: Skipped 130 frames!  The application may be doing too much work on its main thread.

Same W/Resources: Converting to boolean: and same message from Choreographer相同的W/Resources: Converting to boolean:和来自 Choreographer 的相同消息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM