Android: Error creating SupportChartFragment within another fragment


#1

Hello,

I’m using a ViewPager to contain fragments, and would like to embed a Shinobi SupportChartFragment within each fragment. However, I get an exception while inflating the view: 

android.view.InflateException: Binary XML file line #10: Error inflating class fragment

It’s not obvious from the callstack what’s going on, but if I break on exceptions, this is the exception which is causing it (fragment.java):

    public void setRetainInstance(boolean retain) {
        if (retain && mParentFragment != null) {
            throw new IllegalStateException(
                    "Can't retain fragements that are nested in other fragments");               }
       mRetainInstance = retain;
     }

I understand that using a ChartView might be another way of doing it, but I’m reluctant to start out integrating a componnt which requires me to use deprecated code. If in the future Google decided to retire those calls, i’d be stuck.

Is there any other way of making it work?

Thanks,

Sacha


#2

Hi Sacha,

* where I refer to ChartFragment, it is equally applicable to SupportChartFragment

As you have correctly identified, the problem here is that the ChartFragment cannot be nested inside another Fragment. This is because our ChartFragment internally calls the setRetainInstance() method with true, and Android doesn’t allow Fragments to be nested when this method has been called with true.

We do this so that on events like configuration changes, things like the display range of the axes on your chart are maintained. We’re also able to forward on any lifecycle calls from the Fragment to the ShinobiChart meaning the user doesn’t have to think about this (this is required by the OpenGL components within the chart).

When taking the ChartView approach there are two things you need to do:

  1. Forward on the life-cycle calls from the enclosing Fragment or Activity
  2. (optionally) Save any state and restore it as necessary

The first point above is very straight forward - it is simply a case of calling onPause() and onResume() on the ChartView from within the Fragment/Activity’s onPause() and onResume() methods respectively.

The second point needs a little more thought. I take it when you mention deprecated code you are refering to the User Guide entry on How to: Manage Chart Lifecycles? It does indeed talk about using some deprecated methods to ensure the ChartView is retained across configuration changes. However, this is not the only way to achieve this (and could be argued is also not the best way).

Firstly you need to decide whether any state needs retaining. If in your Fragments onCreateView() method you are inflating your layout containing the ChartView, creating and adding your axes and series, and creating and adding your data points then this will be done for every configuration change (i.e. every time you rotate the device). If the user is unable to interact with the chart in any way as to change it from this initial setup then I don’t think you need to do anything further.

However, what is probably most likely is that the user can pan and zoom the chart, thus changing the display range. On a configuration change the range will be set back to whatever it was initially which will probably be a bit weird for the user! So in this case you would want to, using standard (non-deprecated) Android practices for saving and restoring state across configuration changes, save the min and max of the axes and restore the display range after the configuration change. It should just be the case of adding and retrieving a few doubles to the Bundle.

Obviously as the complexity of your app grows, the more you’ll need to think about what needs saving and restoring but in principle this should be a way to achieve this without using deprecated code.

Arguably this work could be done by the ChartView so the user doesn’t have to think about it - it’s definitely something that’s been considered but there hasn’t really been any demand for it and we try to prioritise our development based on customer feedback.

I hope that helps and makes sense! Let me know if you have any further questions or if I’ve misunderstood your original post.

Kind regards,

Patrick