问题描述
比方说,我只有一个Activity
和一个FrameLayout
(我也尝试了新的FragmentContainerView
),所以我将在其中加载Fragments
.假设我有两个片段: fragA 和 fragB ,我将首先加载 fragA ,并在该片段中显示一个按钮, fragB .
Let's say I've got an Activity
with only a FrameLayout
(I've also try with the new FragmentContainerView
) so I will be loading Fragments
on it. Let's assume I've got two Fragments: fragA and fragB, I will first load fragA and with a button, present in that fragment, replace it with fragB.
我在Activity
上定义了一个函数,因此可以在容器上加载新的Fragment
:
I've define a function on my Activity
so I can load a new Fragment
on the container:
public void loadFragment(Fragment fragment) {
FragmentTransaction fragTrans = getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment)
.addToBackStack(null);
fragTrans.commit();
}
我将从 fragA 调用此链接,转到 fragB .到目前为止,一切正常.实际上,我面临的问题与功能无关,是我不喜欢 fragB 的加载时间,大约需要2秒钟,我想向用户显示加载情况,但我无法实现.
And I will call this from fragA to go to fragB. This far so good, everything works fine. Actually the problem I'm facing is not about functioning, is that I don't like the loading time of fragB, it takes about 2sec, and I'd like to display a loading to the user, but I'm not able to achieve it.
我尝试做的第一件事是在容器所在的活动布局中添加已消失 ProgressBar
.然后,我的loadFragment
函数将首先将该ProgressBar设置为可见,然后执行片段事务,并且每个片段将在退出onCreateView
方法之前隐藏( gone )该View.但是问题在于用户从未看到过ProgressBar
,就像在渲染 fragB 的布局时冻结了主UI一样,因此不会更新UI从而使该progressBar变得无用.我什至在LogCat中看到一些跳过的帧大约50帧.
The first thing I've try is adding a gone ProgressBar
to the activity layout, where the container is. Then my loadFragment
function will first set this progressBar visible and then perform the fragment transaction and each fragment will hide (gone) this View before exiting the onCreateView
method. But the problem is that the user never sees this ProgressBar
, it's like the main UI is freezed while rendering the layout of the fragB and therefore does not update the UI making this progressBar usesless. I even see some frame skipped in the LogCat about 50 frames.
两个片段都没有逻辑,只是实现了布局夸大的onCreateView
.我可以注意到,如果将 fragB 的布局更改为一种更简单的布局,则会立即加载,因此我猜测问题与呈现布局所需的时间有关.这种 heavy 布局是一种非常大的形式,其中包含许多TextInputLayout
和TextInputEditText
和MaterialSpinner
(来自GitHub).
Both fragments have no logic just the onCreateView
implemented where the layout is inflated. I can notice that if I change the layout of fragB to a simpler one it loads instantly, so I'm guessing the issue is related to the time it takes to render the layout. This heavy layout is a really big form with lots of TextInputLayout
with TextInputEditText
and MaterialSpinner
(from GitHub).
我知道我可以简化布局,但是我想知道如何在渲染时显示负载.例如,我已经看到一些应用在加载时加载某种 dummy-view ,然后将其替换为真实数据.
I know I maybe can simplify the layout, but I'd like to know how can I display a loading while rendering. For example, I've seen some apps load some kind of dummy-view while loading and then replace it with real data.
我尝试做的一件事是加载一个 dummy 布局,中间放置一个ProgressBar
,在onCreateView
方法中发布一个Handler
来充气一个 real 在后台的同一容器中进行布局,如下所示:
One thing I've try is to load a dummy layout with a ProgressBar
in the middle and in the onCreateView
method post a Handler
to inflate a real layout on the same container in the background, like this:
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_dummy, container, false);
Handler mHandler = new Handler();
mHandler.post(new Runnable() {
@Override
public void run() {
container.removeAllViews();
View realView = inflater.inflate(R.layout.fragment_real, container);
}
});
}
这有点工作,因为观看体验很好,但是当向后浏览时, fragB 的布局仍可作为其他片段的背景看到.我还没有测试它,但是也许我可以在退出该片段之前调用container.removeAllViews();
,它可以工作,但对我来说似乎仍然是一种解决方法,而不是解决方案.
This kinda work, as the viewing experience is nice, but when navigating back, the layout of fragB remains visible as background of the other fragments. I have not test it but maybe I can call container.removeAllViews();
before exiting the fragment and it will work, but still seems like a workaround rather than a solution, to me.
我还没有尝试过的另一件事,因为这可能是一个过大的杀伤力,那就是拥有一个 intermediate (中间)或 loading (加载)片段,并始终将其加载到真正的片段之前,并且我将向它传递一个Intent Extra,以便告诉我要显示的真正片段是什么.此中间片段将不会添加到后台.
And other thing I've not try because maybe is an over-kill is to have an intermediate or loading fragment and load it always before the real fragment, and I will pass an Intent Extra to it so I can tell what's the real fragment I want to display. This intermediate fragment will not be added to the backstack.
您如何解决此类问题?
推荐答案
好吧,看来AsyncLayoutInflater
是最好的选择!
Well it seems that AsyncLayoutInflater
is the way to go!
这是我的用法:
private ViewGroup fragmentContainer;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View dummyView = inflater.inflate(R.layout.fragment_dummy_loading, container, false);
fragmentContainer = container;
AsyncLayoutInflater asyncLayoutInflater = new AsyncLayoutInflater(getContext());
asyncLayoutInflater.inflate(R.layout.fragment_real_layout, container, new AsyncLayoutInflater.OnInflateFinishedListener() {
@Override
public void onInflateFinished(@NonNull View view, int resid, @Nullable ViewGroup parent) {
fragmentContainer.removeAllViews();
fragmentContainer.addView(view);
}
});
return dummyView;
}
@Override
public void onStop() {
super.onStop();
fragmentContainer.removeAllViews();
}
在那儿, fragment_dummy_loading 是具有ProgressBar
的布局,而 fragment_real_layout 是真正的沉重布局.
Up there, fragment_dummy_loading is a layout with a ProgressBar
and fragment_real_layout is the real heavy layout.
我一无所获...这就是我如何将对象绑定到XML小部件(,如果可能的话,不使用Android数据绑定)当AsyncLayoutInflater
退回到UI线程中.
There's just one thing I don't get... and that's how can I bind Objects to the XML widgets (without using Android Data Binding, if possible) when the AsyncLayoutInflater
fallsback to infalte in the UI thread.
根据文档:
然后我检查了AsyncLayoutInflater
的来源,可以知道无论膨胀是在后台还是在主线程中,都调用了 onInflateFinished 方法
And I check the source of AsyncLayoutInflater
and I can tell that the method onInflateFinished is called no matter if the inflation was in the background or in the main thread
这篇关于Android Fragment在渲染布局时显示加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!