Android Fragment在渲染布局时显示加载 [英] Android Fragment display a loading while rendering layout

查看:623
本文介绍了Android Fragment在渲染布局时显示加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

比方说,我只有一个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 布局是一种非常大的形式,其中包含许多TextInputLayoutTextInputEditTextMaterialSpinner(来自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将自动退回到UI线程上膨胀.

If the layout that is trying to be inflated cannot be constructed asynchronously for whatever reason, AsyncLayoutInflater will automatically fall back to inflating on 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在渲染布局时显示加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆