安卓系统上布局时间过长的ANR警告

1 人关注

我一直在努力开发应用程序。在建立我的应用程序时,我在logcat上得到onLayout时间太长的ANR警告。所以我的问题是,问题到底出在哪里?

ANR Warning]onLayout time too long, this =android.widget.FrameLayout{b7ebc83 V.E...... ......ID 0,0-720,1200 #7f0b005f app:id/content}time =651 ms
 D/View: [ANR Warning]onLayout time too long, this =android.widget.LinearLayout{2b85e00 V.E...... ......ID 0,0-720,1200}time =652 ms
 D/View: [ANR Warning]onLayout time too long, this =android.widget.FrameLayout{9243639 V.E...... ......ID 0,96-720,1296 #7f0b0065 app:id/view_content}time =652 ms
 D/View: [ANR Warning]onLayout time too long, this =android.widget.LinearLayout{606a47e V.E...... ......ID 0,0-720,1296}time =654 ms
 D/View: [ANR Warning]onLayout time too long, this =android.support.v7.widget.ContentFrameLayout{e669ddf V.E...... ......ID 0,0-720,1296 #1020002 android:id/content}time =654 ms
 D/View: [ANR Warning]onLayout time too long, this =android.support.v7.widget.FitWindowsLinearLayout{f455a2c V.E...... ......ID 0,0-720,1296 #7f0b004b app:id/action_bar_root}time =655 ms
 D/View: [ANR Warning]onLayout time too long, this =android.widget.FrameLayout{c08fcf5 V.E...... ......ID 0,48-720,1344}time =655 ms 
 D/View: [ANR Warning]onLayout time too long, this =android.widget.LinearLayout{7648a8a V.E...... ......ID 0,0-720,1344}time =656 ms
 D/View: [ANR Warning]onLayout time too long, this =DecorView@23d1963[MainActivity]time =656 ms

以下是我遇到上述问题的应用程序布局文件

fragment_video_browser.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_video"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view1_video"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical" />
    <!--/>-->
    <!--android:background="@color/novided_bg"-->
</LinearLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"/>

activity_title_base.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/toolbar_height"
        android:background="?attr/colorPrimary"
        android:fitsSystemWindows="true"
        app:contentInsetEnd="0dp"
        app:contentInsetStart="0dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/toolbar_height"
            android:gravity="center_vertical"
            android:orientation="horizontal">
            <ImageView
                android:id="@+id/back"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="@dimen/toolbar_backmenu_margin_start"
                android:background="?android:attr/actionBarItemBackground"
                android:clickable="true"
                android:src="@mipmap/back"
                android:visibility="invisible" />
            <TextView
                android:id="@+id/title_text"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:lines="1"
                android:textColor="@color/toolbar_title_color"
                android:textDirection="locale"
                android:textSize="@dimen/toolbar_title_size" />
            <ImageView
                android:id="@+id/menu"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginEnd="@dimen/toolbar_menu_marginend"
                android:background="?android:attr/actionBarItemBackground"
                android:clickable="true"
                android:paddingEnd="@dimen/toolbar_menu_padding"
                android:paddingStart="@dimen/toolbar_menu_padding"
                android:src="@drawable/ic_more"
                android:visibility="gone"/>
            <ImageView
                android:id="@+id/edit"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginEnd="@dimen/toolbar_menu_marginend"
                android:background="?android:attr/actionBarItemBackground"
                android:clickable="true"
                android:paddingEnd="@dimen/toolbar_menu_padding"
                android:paddingStart="@dimen/toolbar_menu_padding"
                android:src="@drawable/ic_btn_edit"
                android:visibility="gone" />
            <TextView
                android:id="@+id/all_select"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/toolbar_selectall_margin_end"
                android:background="?android:attr/selectableItemBackgroundBorderless"
                android:textColor="@color/toolbar_selectall_color"
                android:textDirection="locale"
                android:textSize="@dimen/toolbar_selectall_textsize"
                android:visibility="gone" />
        </LinearLayout>
    </android.support.v7.widget.Toolbar>
    <FrameLayout
        android:id="@+id/view_content"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>
</LinearLayout>

fragment.java

public class VideoBrowserFragment extends BaseFragment implements LoaderManager.LoaderCallbacks<Cursor>,
        VideoBrowserAdapter.OnRecyclerViewItemClickListener,
        VideoBrowserAdapter.OnItemLongClickListener,
        EditionMode.OnEditionModeListener {
    public final static String TAG = "Video/VideoBrowserFragment";
    private int defaultSort = MediaInfoComparator.SORT_BY_NAME;
    protected VideoBrowserAdapter mAdapter;
    private VideoBrowserData videoMedia;
    private View view;
    private String bucketID;
    private String bucketName;
    private UiHanlder uiHanlder = new UiHanlder();
    private class UiHanlder extends Handler {
        @Override
        public void handleMessage(final Message msg) {
            ((BaseActivity) getActivity()).onBackPressed();
    @Override
    public boolean onBackPressed() {
        if (editionMode != null) {
            if (editionMode.inEdionModle) {
                editionMode.leaveEdition();
                if (videoMedia != null && videoMedia.videoArrayList.size() == 0) {
                    return false;
                } else {
                    return true;
        } else {
            this.onDestroy();
        return false;
    @Override
    public boolean inEditModel() {
        if (editionMode == null) {
            return false;
        if (editionMode.inEdionModle) {
            if (editionMode.selectionManager.getCheckedItemsCount() == mAdapter.getItemCount()) {
                editionMode.allNotSelect();
            } else {
                editionMode.allSelect((ArrayList<VideoInfoBean>) videoMedia.videoArrayList.clone());
        } else {
            editionMode.inEdition();
        return false;
    @Override
    public boolean sortByType(int type) {
        if (videoMedia == null) {
            return false;
        sortData(type);
        defaultSort = type;
        return false;
    private void sortData(int type) {
        Collections.sort(videoMedia.videoArrayList, MediaInfoComparator.getInstance(type));
        mAdapter.setData(videoMedia.videoArrayList);
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle bundle = getArguments();
        if (bundle != null) {
            bucketID = bundle.getString(FileBrowserFragment.BUCKETID);
            bucketName = bundle.getString(FileBrowserFragment.BUCKETNAME);
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d("MY_LOG", "vdo FRAGMENT started");
        super.onCreateView(inflater, container, savedInstanceState);
        view = inflater.inflate(R.layout.fragment_video_browser, container, false);
        init();
        Log.d("MY_LOG", "vdo FRAGMENT ended");
        return view;
    private void init() {
        ((BaseActivity) getActivity()).setTitleText(bucketName);
        ((BaseActivity) getActivity()).setBackVisible();
        ((BaseActivity) getActivity()).setAllSelectVisible(View.GONE);
        ((BaseActivity) getActivity()).setEditVisible(View.GONE);
        ((BaseActivity) getActivity()).setMenuVisible(View.VISIBLE);
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this.getContext());
        layoutManager.setAutoMeasureEnabled(false);
        mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view1_video);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setItemViewCacheSize(20);
        mRecyclerView.setDrawingCacheEnabled(true);
        mRecyclerView.setDrawingCacheBackgroundColor(View.DRAWING_CACHE_QUALITY_HIGH);
        mRecyclerView.setLayoutManager(layoutManager);
        mAdapter = new VideoBrowserAdapter(this.getContext());
        mAdapter.mThumbnailCache = new ThumbnailCache(getContext());
        mRecyclerView.setAdapter(mAdapter);
//        mRecyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL_LIST));
//        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        mAdapter.setOnItemClickListener(this);
        mAdapter.setOnItemClickLongListener(this);
        getLoaderManager().initLoader(1, null, this);
        editionMode = new EditionMode(this, (BaseVideoActivity) this.getActivity(), mAdapter, getContext(), view, R.id.fragment_video);
        editionMode.setOnEditionModeListener(this);
        mAdapter.mActionMode = editionMode;
        mAdapter.mThumbnailCache.addListener(mAdapter);
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        videoMedia = new VideoBrowserData(this.getContext());
        return videoMedia.getCursorLoader(bucketID);
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        if (videoMedia == null) {
            videoMedia = new VideoBrowserData(this.getContext());
        if (data != null && videoMedia != null) {
            videoMedia.queryAllVideo(data);
            setPlayInfo();
            sortData(defaultSort);
            if (editionMode.inEdionModle) {
                editionMode.refreshCheckedItem((ArrayList<VideoInfoBean>) videoMedia.videoArrayList.clone());
                editionMode.updateAllSize();
            if (videoMedia.videoArrayList.size() == 0) {
                uiHanlder.sendEmptyMessage(0);
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    @Override
    public void onResume() {
        super.onResume();
        if (videoMedia == null) {
            getLoaderManager().restartLoader(0, null, this);
            return;
        setPlayInfo();
        mAdapter.notifyDataSetChanged();
    @Override
    public void onDestroy() {
        Log.d("onDestroy", "onDestroy");
        if (mAdapter != null) {
            mAdapter.clearCachedHolder();
            if (mAdapter.mThumbnailCache != null) {
                mAdapter.mThumbnailCache.clear();
                mAdapter.mThumbnailCache = null;
        getLoaderManager().destroyLoader(1);
        super.onDestroy();
    @Override
    public void onItemClick(View view, RecyclerView.ViewHolder data) {
        Log.i(TAG, "onItemClick video : inEdionModle:" + editionMode.inEdionModle);
        final Object obj = view.getTag();
        int index = 0;
        if (obj == null || !(obj instanceof RecyclerView.ViewHolder)) {
            return;
        if (editionMode.inEdionModle) {
            editionMode.select((VideoBrowserAdapter.VideoViewHolder) obj);
        } else {
            for (int i = 0; i < videoMedia.videoArrayList.size(); i++) {
                if (((BaseAdapter.VideoViewHolder) data).mId == videoMedia.videoArrayList.get(i).mediaID) {
                    index = i;
                    break;
            VideoActivity.startPlayVideoList(getActivity(), index, videoMedia.videoArrayList);
    @Override
    public void onItemLongClick(View view, RecyclerView.ViewHolder data) {
        final Object obj = view.getTag();
        if (obj == null || !(obj instanceof RecyclerView.ViewHolder)) {
            return;
        editionMode.inEditionSelect((VideoBrowserAdapter.VideoViewHolder) obj);
    public void setPlayInfo() {
        for (int i = 0; i < videoMedia.videoArrayList.size(); i++) {
            VideoInfoBean videoInfoBean = videoMedia.videoArrayList.get(i);
            float index = VideoActivity.getLastPlayedVidePosition(videoInfoBean.mediaPath);
            if (index == 0.0) {
                videoInfoBean.playIndex = null;
            } else {
                videoInfoBean.playIndex = Utils.getIndex(index);
            if (VideoActivity.getLastPlayedVideo() != null) {
                if (VideoActivity.getLastPlayedVideo().equals(String.valueOf(videoInfoBean.mediaPath))) {
                    videoInfoBean.isLastPlay = true;
                } else {
                    videoInfoBean.isLastPlay = false;
    @Override
    public int getAllSize() {
        return videoMedia.videoArrayList.size();

编辑:在降低回收器视图的布局高度至300dp时,我没有收到警告。

5 个评论
Mike
你能分享你的布局文件吗?
当你长时间阻塞主线程时就会发生这种情况。你是否有什么东西阻塞它,比如调用数据库和处理大量数据?
@Mike 我用所需的布局文件更新了这个问题。
@Sayem 是的,我有。但即使删除了所有的调用,不让应用程序获取数据,我仍然面临这个问题。
你的布局是非常简单的。你的布局不可能发生这种情况。请检查你的总代码中那些长时间的运行处理。有些时候,如果你的设备运行在低运行内存上,就会发生这种情况。还有一件事,在你的imageView中不要使用大的drawable或图片。
android
android-layout
performance-testing
Kamal Kumar Majhi
Kamal Kumar Majhi
发布于 2018-09-13
1 个回答
KE Keronei
KE Keronei
发布于 2022-03-02
0 人赞同

从你的布局来看,除了fragment_video_browser的LinearLayout中的填充_父母之外,一切似乎都很好。

这就是你所有问题的根源。 填充_父母 ,现在由match_parent取代,在android文档中有这样的描述。

FILL_PARENT(在API Level 8和更高版本中更名为MATCH_PARENT),这意味着视图要和它的父本一样大(减去填充)。

当你的线性布局不断地扩展它的高度,而它的子代RecyclerView有match_parent作为它的高度属性时,达到最大可用高度的竞赛永远不会结束,直到RecyclerView中的所有项目都已经准备好--尽管没有显示。

在这个层面上,拥有recyclerView的意义变得毫无意义,因为它的主要功能是在用户滚动时回收项目,但当它一次性准备好所有项目时,它只是作为一个静态视图,需要一些时间来准备。

From your edit,

在降低回收器视图的布局高度到300dp时,我没有得到警告。

它清楚地表明,如果你把高度限制在这个值,recyclerView适配器只是准备了足够的项目来显示在视口内,这是很迅速的,然后当你滚动时,根据滚动的方向准备更多的项目。

一个快速的解决方案是取消对最大可用高度的追逐,在回收器中使用wrap_content。

其他原因包括在NestedScrollView中嵌套recyclerView,以及其他任何有可扩展/可滚动视图而不注意为recyclerView提供高度参数的情况。

下面是文档中的一个例子,说明如何利用recyclerView的力量。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginLeft="@dimen/margin_medium"
android:layout_marginRight="@dimen/margin_medium"
android:gravity="center_vertical">
<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/element_text"/>

这个ANR问题在项目少的情况下不会出现,但随着列表的增加,比如说100个项目或更多,你就会开始遇到这个问题。