AnR警告Android上的布局时间太长 [英] ANR warning onLayout time too long on Android
问题描述
我一直致力于开发应用程序。在构建我的应用程序时,我得到了On Layout Time Too Long Layout Time Too Layout Time Too Long和LogCAT警告。所以我的问题是,到底是什么问题?
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>
active_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"/>
ACTIVATION_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时,我没有收到警告。
推荐答案
从您的布局来看,除了Fragment_Video_Browser的LinearLayout中的Fill_Parent之外,其他一切似乎都很好。
这就是你所有问题的根源,fill_parent,现在被Match_Parent取代在Android文档中有这样的描述;
Fill_Parent(在API级别8及更高版本中重命名为Match_Parent),这意味着视图希望与其父视图一样大(减去填充)
如果您的线性布局不断地扩展其高度,并且其子对象RececumerView的高度属性为Match_Parent,则达到最大可用高度的竞赛永远不会到达终点,直到RececurerView中的所有项目都已准备就绪-尽管没有显示。
在此级别上,拥有RececurerView的意义变得毫无意义,因为它的主要功能是在用户滚动时回收项目,但当它一次准备所有项目时,它只是作为一个静态视图,需要一些时间才能准备好。
从您的编辑,
将回收器视图的布局高度降低到300dp时,我没有收到警告。
它清楚地说明,如果您将高度限制为该值,RececumerView适配器只准备足够在该视口中显示的项目,这很快,然后当您滚动时,会根据滚动方向准备更多项目。
一种快速的解决方法是消除对最大可用高度的追求,并在回收器中使用WRAP_CONTENT。
其他原因包括在NestedScrollView以及具有可展开/可滚动视图的任何其他视图中嵌套RececurerView,而不注意为RececurerView提供的高度参数。
这里是文档中的一个示例,说明如何利用RececumerView来实现其功能。
<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个或更多项目,您将开始遇到此问题。
要确定在调整布局参数后是否已修复此问题,一个简单的测试是记录在该覆盖内的onBindViewHolder中绑定的项,如下所示:
Log.d("TAG", "Binding item at position $position")
如果一切正常,该函数将在您滚动时以位为单位打印输出,但如果它一次打印所有项目,则您尚未解决问题-假设您的所有项目无法在一个屏幕上显示,需要滚动以获得更多。
阅读有关docs的更多信息。
这篇关于AnR警告Android上的布局时间太长的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!