Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.lang.illegalstateexception: a factory has already been set on this layoutinflater

I have tried to change the background color of options menu in my android app. I am using ActionBarSherlock library. I have tried this code for changing the background color of options menu

https://stackoverflow.com/a/8475357/584095

But I ended up with an exception "java.lang.illegalstateexception: a factory has already been set on this layoutinflater" at line

LayoutInflater.setFactory();

I don't know what is wrong in this code. Can anyone help me in resolving this issue?

like image 349
samvijay Avatar asked Nov 16 '12 11:11

samvijay


4 Answers

There been a change in support library since version 22.1.0.

You will get an IllegalStateException if you try to call getLayoutInflater().setFactory()

You should use the new api

  • LayoutInflaterCompat.setFactory()
  • AppCompatActivity instead of deprecated ActionBarActivity

Or simply use the old version

  • com.android.support:appcompat-v7:22.0.0
  • com.android.support:appcompat-v4:22.0.0
like image 120
Ilya Gazman Avatar answered Nov 20 '22 16:11

Ilya Gazman


This happens because you are using compatibility library. It sets own Factory to deal with platform specific layouts. You may try to set own factory in onCreate() method before calling super.onCreate(). This will disallow compatibility library to override factory and you will be unable to inflate fragments from xml files, but styling should work.

like image 23
user711058 Avatar answered Nov 20 '22 17:11

user711058


To keep compatibility library working and avoid "java.lang.illegalstateexception: a factory has already been set on this layoutinflater", you need to get a final reference to the already set Factory and call its onCreateView within your own Factory.onCreateView. Before that an introspection trick must be use to allow you to set one more time a Factory to the LayoutInflater :

LayoutInflater layoutInflater = getLayoutInflater();
final Factory existingFactory = layoutInflater.getFactory();
// use introspection to allow a new Factory to be set
try {
    Field field = LayoutInflater.class.getDeclaredField("mFactorySet");
    field.setAccessible(true);
    field.setBoolean(layoutInflater, false);
    getLayoutInflater().setFactory(new Factory() {
        @Override
        public View onCreateView(String name, final Context context, AttributeSet attrs) {
            View view = null;
            // if a factory was already set, we use the returned view
            if (existingFactory != null) {
                view = existingFactory.onCreateView(name, context, attrs);
            }
            // do whatever you want with the null or non-null view
            // such as expanding 'IconMenuItemView' and changing its style
            // or anything else...
            // and return the view
            return view;
        }
    });
} catch (NoSuchFieldException e) {
    // ...
} catch (IllegalArgumentException e) {
    // ...
} catch (IllegalAccessException e) {
    // ...
}
like image 5
avianey Avatar answered Nov 20 '22 16:11

avianey


This works for me:

LayoutInflater inflater = LayoutInflater.from(context);
if (inflater.getFactory() != null) {
    inflater = inflater.cloneInContext(context);
}
inflater.setFactory(factory);
like image 3
ayepin Avatar answered Nov 20 '22 17:11

ayepin