Custom Layout Inflation with Fragments in Robolectric not working - android

When inflating a layout in a Fragment, with the LayoutInflater, i am getting this exception:
./res/layout/locations_list.xml line #-1 (sorry, not yet implemented): Error inflating class com.costum.android.widget.LoadMoreListView
I figured out that this is happening when inflating a custom layout in
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.locations_list, container, false);
}
Edit This is the locations_list.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:orientation="vertical" >
<com.costum.android.widget.LoadMoreListView
android:id="#+id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="0dp" />
</LinearLayout>
any other layout inflator works, like in this test:
#Test
public void testInflator() {
ActivityController<SherlockFragmentActivity> activityController = CustomTestRunner
.startActivity();
SherlockFragmentActivity activity = activityController.get();
LayoutInflater from = LayoutInflater.from(activity);
View view = from
.inflate(com.twisper.R.layout.locations_list_item, null);
assertNotNull(view);
}
I am using Robolectric with the 2.2-SNAPSHOTs , Now my question is how could I work around this issue or how could I implement the missing functionality, the robolectric documentation is very sparse, hence I had trouble to find any starting point.
Full Stack Trace
android.view.InflateException: XML file ./res/layout/locations_list.xml line #-1 (sorry, not yet implemented): Error inflating class com.costum.android.widget.LoadMoreListView
at android.view.LayoutInflater.createView(LayoutInflater.java:613)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
...
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createView(LayoutInflater.java:587)
at android.view.LayoutInflater.createView(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createViewFromTag(LayoutInflater.java:687)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.rInflate(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:396)
at android.view.LayoutInflater.inflate(LayoutInflater.java)
...
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -9
at java.lang.String.substring(String.java:1911)
at org.robolectric.res.ResName.qualifyResName(ResName.java:50)
at org.robolectric.res.Attribute.getResourceReference(Attribute.java:138)
at org.robolectric.res.Attribute.qualifiedValue(Attribute.java:127)
at org.robolectric.res.builder.XmlFileBuilder$XmlResourceParserImpl.qualify(XmlFileBuilder.java:316)
at org.robolectric.res.builder.XmlFileBuilder$XmlResourceParserImpl.getAttributeValue(XmlFileBuilder.java:340)
at org.robolectric.shadows.ShadowResources.findAttributeValue(ShadowResources.java:252)
at org.robolectric.shadows.ShadowResources.attrsToTypedArray(ShadowResources.java:188)
at org.robolectric.shadows.ShadowResources.access$000(ShadowResources.java:51)
at org.robolectric.shadows.ShadowResources$ShadowTheme.obtainStyledAttributes(ShadowResources.java:460)
I also posted the issue on robolectrics issue tracker.

I figured it out, and if you got stock to such an situation just look for your IDs in the XML, even though
android:id="#+id/android:list"
is often seen in some example code it must be:
android:id="#android:id/list"

The last version of Robolectric (3.0-Snapshot) has some problems with customized views.
To fix that, do the follow:
In the module app where your code is, create a file called project.properties, at the same level as AndroidManifest.xml
Fill the content with reference to the class folder of build. e.g. for StaggeredGridView:
android.library.reference.1=../../build/intermediates/exploded-aar/com.etsy.android.grid/library/1.0.5
Here you must check three things:
There should be one line per reference
Each reference has one number (1, 2, 3), which should be increase by one each time
The version number folder at the end must match with the version number in your build.gradle file.
You have an example of project working here:
https://github.com/jiahaoliuliu/RobolectricSample/blob/master/app/src/main/project.properties

In my case I got this problem when I had this in my app:
<dependency>
<groupId>com.google.android</groupId>
<artifactId>support-v4</artifactId>
<version>r13</version>
</dependency>
but this in my unittest project:
<dependency>
<groupId>com.google.android</groupId>
<artifactId>support-v4</artifactId>
<version>r7</version>
</dependency>
The older version of the support library I used in the tests didn't contain the class I was trying to use (android.support.v4.widget.DrawerLayout).

In my case, my FragmentActivity XML was inflating a Fragment that was expecting a Bundle. I swapped the XML for a FrameLayout holder and added the fragment with the proper bundle in the activity.

Related

Inflating class android.support.v4.widget.SwipeRefreshLayout

I am trying to implement SwipeRefreshLayout in fragments. It is looking created correctly, but I continue to get the errors:
Caused by: android.view.InflateException: Binary XML file line #2:
Binary XML file line #2: Error inflating class
android.support.v4.widget.SwipeRefreshLayout
Caused by: android.view.InflateException: Binary XML file line #2:
Error inflating class android.support.v4.widget.SwipeRefreshLayout
Caused by: java.lang.ClassNotFoundException: Didn't find class
"android.support.v4.widget.SwipeRefreshLayout" on path:
DexPathList[[zip file "/data/app/com.weather.rainy-
2/base.apk"],nativeLibraryDirectories=[/data/app/com.weather.rainy-
2/lib/x86, /system/lib, /vendor/lib]]
I really don't have any idea what is causing this.
My fragment layout for implementing the SwipeRefreshLayout:
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/swipeToRefresh4Maps"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/topRL4Maps"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bg_gradient_purple"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingTop="64dp"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingBottom="64dp"
tools:context="com.weather.rainy.ui.MapsActivity">
<TextView
android:id="#+id/yourLocationLabelTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="15dp"
android:text="#+string/your_location"
android:textColor="#android:color/white"
android:textSize="24sp" />
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/addressValueTextView"
android:layout_alignBottom="#+id/addressValueTextView"
android:layout_below="#+id/yourLocationLabelTextView"
android:layout_centerHorizontal="true"
android:layout_margin="15dp"
tools:context="com.weather.rainy.ui.MapsActivity" />
<TextView
android:id="#+id/addressValueTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/map"
android:layout_alignEnd="#+id/map"
android:layout_alignParentStart="false"
android:layout_alignParentBottom="true"
android:text="#+string/..."
android:textColor="#aaffffff"
android:textSize="18sp" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
And, my fragment class for calling the SwipeRefreshLayout:
//Code for Swipe Refresh
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeToRefresh4Maps);
mSwipeRefreshLayout.setColorSchemeResources(R.color.Red, R.color.Orange, R.color.Blue, R.color.Green);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
Log.v(TAG, "************** MAPS - SWIPE REFRESH EVENT TRIGGERED!!!!!");
findLocation();
}
});
I really don't have any clue, what is the wrong. Any help is greatly appreciated.
Because you are using AndroidX, your XML is referencing the wrong version of SwipeRefreshLayout
Change in your XML from android.support.v4.widget.SwipeRefreshLayout to androidx.swiperefreshlayout.widget.SwipeRefreshLayout
I was stuck on the SwipeRefreshLayout using AndroidX
I was not able to get Reference of SwipeRefreshLayout in AndroidX
So I added implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
dependency in app level gradle file.
So in my case solution is,
Add the dependency in app level build.gradle file
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
This issue seems to happen when migrating to AndroidX as there are many build artifact to be changed when Migrating to AndroidX.
Solution 1: Do it manually
For exemple:
android.support.v4.widget.SwipeRefreshLayout changed to => androidx.swiperefreshlayout.widget.SwipeRefreshLayout
You must update all the build artifact listed in Migrating to AndroidX
Solution 2: Automate on Android Studio 3.2+
As suggested in this same link, you could automate this process by selecting Refactor > Migrate to AndroidX from the menu bar.
ADDITIONAL INFO - The errors I had:
Error inflating class android.support.constraint.ConstraintLayout
element WebView is not allowed here
Gradle needs to new dependency which is AndroidX:
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
If you use SwipeRefreshLayout in Java class, you can see this line:
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
In you XML file, you should use the tags of SwipeRefreshLayout:
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout

Missing resources for Android CardView library

I'm using CardView in my project and I'm getting an error on older devices:
E android.view.InflateException: Binary XML file line #25: Error inflating class android.support.v7.widget.CardView
E at android.view.LayoutInflater.createView(LayoutInflater.java:518)
E at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:570)
E at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
E at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)
E at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
E at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
Seems similar to a few questions on SO such as this one
My problem is that the solution for that questions feels very hacky and that's understandable as the answer was given last year when Lollipop just entered the public preview. Have things changed since? How do I get the resources?
I've tried a few things such as importing .aar as a module but nothing seems to work. I've followed the official documentation on how to add support libraries (https://developer.android.com/tools/support-library/setup.html#libs-with-res) but that didn't work. Also according to that link - there doesn't seem to be any difference between adding libraries with and without resources for Android Studio?
My app build.gradle includes the following dependencies:
compile 'com.android.support:appcompat-v7:21.0.3'
compile 'com.android.support:cardview-v7:21.0.3'
compile 'com.android.support:recyclerview-v7:21.0.3'
CardView layout is used here
<android.support.v7.widget.CardView
xmlns:card="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?android:attr/selectableItemBackground"
card:cardCornerRadius="6dp"
card:cardUseCompatPadding="true"
tools:ignore="NewApi">
EDIT: the problem noticed on Samsung S2 2.3 - API 19+ works fine
?android:attr/selectableItemBackground is platform related, use it without android: prefix to refer to AppCompat's attribute.

use custom view from library project in my case

I have made an Android main library project, in which I have created a custom view class:
package com.my.android.library.layout;
public class CustomView extends View {
...
I also defined styleable for my CustomView:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomView">
<attr name="title_text" format="string" />
</declare-styleable>
</resources>
Since I don't want to share my source code to others who are using my library project, so I created an distributed library project, in which I added the jar of above main library project to libs/ folder of distributed library project and copied all resource from main library project to distributed library project.
NEXT, I have made an android app project which uses the distributed library project. In the main layout file of app project, I defined the following :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.my.android.library.layout.CustomView
custom:title_text = "THIS IS TITLE"
/>
<RelativeLayout>
When I run my app, I got the following exception:
E/AndroidRuntime(30993): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.android.app/com.my.android.app.MainActivity}: android.view.InflateException: Binary XML file line #7: Error inflating class com.my.android.library.layout.CustomView
E/AndroidRuntime(30993): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2071)
E/AndroidRuntime(30993): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2096)
...
Caused by: java.lang.ClassNotFoundException: com.my.android.library.layout.CustomView
E/AndroidRuntime( 2947): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)
E/AndroidRuntime( 2947): at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
E/AndroidRuntime( 2947): at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
E/AndroidRuntime( 2947): at android.view.LayoutInflater.createView(LayoutInflater.java:552)
E/AndroidRuntime( 2947): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
It seems it can not inflate the my CustomView in layout xml. Why? How to get rid of it?
(I checked the main library jar file, there is CustomView class. Please don't just throw me a link of Android website without explanation.)
Since you are adding the View from a jar, you should be able to specify the namespace as:
xmlns:custom="http://schemas.android.com/apk/lib/root_package_name
Where "root_package_name" could be "com.my.android.library.layout" or "com.my.android.library" or something like that.
If that doesn't work, then it's probably and "Order and Export" problem or the way you are adding the library. Make sure the library is included properly:
Android Activity ClassNotFoundException - tried everything
And finally, if that also fails, then you might need to update Android SDK:
ClassNotFoundException: Didn't find class "com.google.android.gms.ads.AdView"
Let's try do it this way:
public CustomView(Context context) {
this(context, null, 0);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//init your stuff here
}
Could you give us full stacktrace of the exception ?

Testing custom Views with Robolectric

I'm trying to run unit tests with Robolectric 2.1.1 and I cannot get it to inflate custom layouts (e.g. ViewPagerIndicator classes).
Suppose this is my layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="test"
android:id="#+id/test_test"/>
<com.viewpagerindicator.CirclePageIndicator
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Consider this my test class:
#RunWith(RobolectricTestRunner.class)
public class TestRoboActivityTest {
private TestRoboActivity mActivity;
#Before
public void setUp() throws Exception {
mActivity = Robolectric.buildActivity(TestRoboActivity.class).create().get();
}
#After
public void tearDown() throws Exception {
mActivity = null;
}
#Test
public void testSanity() throws Exception {
Assert.assertNotNull(mActivity);
}
}
Executing 'mvn clean test' results in
Tests in error:
testSanity(TestRoboActivityTest): XML file .\res\layout\test.xml line #-1 (sorry, not yet implemented): Error inflating class com.viewpagerindicator.CirclePageIndicator
Cool, so it seems like custom views aren't supported yet. Checking the sample Robolectric project on their website,
one solution could be to inflate the layout from LayoutInflater:
#RunWith(RobolectricTestRunner.class)
public class TestRoboActivityTest {
private View mTestRoboActivityView;
#Before
public void setUp() throws Exception {
mTestRoboActivityView = LayoutInflater.from(new Activity()).inflate(R.layout.test, null);
}
#After
public void tearDown() throws Exception {
mTestRoboActivityView = null;
}
#Test
public void testSanity() throws Exception {
Assert.assertNotNull(mTestRoboActivityView);
}
}
which results in:
Tests in error:
testSanity(TestRoboActivityTest): XML file .\res\layout\test.xml line #-1 (sorry, not yet implemented): Error inflating class com.viewpagerindicator.CirclePageIndicator
My last resort was trying to use shadow classes:
#Implements(CirclePageIndicator.class)
public class CirclePageIndicatorShadow implements PageIndicator {
#Override
#Implementation
public void setViewPager(ViewPager view) {
// Stub
}
// etc.
}
and using #Config(shadows = {CirclePageIndicatorShadow.class}). This again resulted in
Tests in error:
testSanity(TestRoboActivityTest): XML file .\res\layout\test.xml line #-1 (sorry, not yet implemented): Error inflating class com.viewpagerindicator.CirclePageIndicator
Edit (December 2014)
Please note that the following stracktrace was added later by David Rabinowitz. While related, it is not the issue I was facing at the time.
Here is the stack trace:
android.view.InflateException: XML file .\res\layout\activity_home.xml line #-1 (sorry, not yet implemented): Error inflating class com.test.custom.RobotoTextView
at android.view.LayoutInflater.createView(LayoutInflater.java:613)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
at org.robolectric.tester.android.view.RoboWindow.setContentView(RoboWindow.java:82)
at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.java:273)
at android.app.Activity.setContentView(Activity.java)
at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.java:12)
at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.java:28)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:241)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:177)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createView(LayoutInflater.java:587)
at android.view.LayoutInflater.createView(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createViewFromTag(LayoutInflater.java:687)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.rInflate(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:396)
at android.view.LayoutInflater.inflate(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:352)
at android.view.LayoutInflater.inflate(LayoutInflater.java)
at org.robolectric.tester.android.view.RoboWindow.setContentView(RoboWindow.java:82)
at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.java:273)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.robolectric.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.java:455)
at android.app.Activity.setContentView(Activity.java)
at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.java:12)
at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
... 22 more
Caused by: java.lang.RuntimeException: error converting RobotoMedium.ttf using EnumConverter
at org.robolectric.shadows.Converter.convertAndFill(Converter.java:150)
at org.robolectric.shadows.Converter.convertAndFill(Converter.java:50)
at org.robolectric.shadows.ShadowResources.createTypedArray(ShadowResources.java:228)
at org.robolectric.shadows.ShadowResources.attrsToTypedArray(ShadowResources.java:203)
at org.robolectric.shadows.ShadowResources.access$000(ShadowResources.java:51)
at org.robolectric.shadows.ShadowResources$ShadowTheme.obtainStyledAttributes(ShadowResources.java:460)
at android.content.res.Resources$Theme.obtainStyledAttributes(Resources.java)
at android.widget.TextView.__constructor__(TextView.java:561)
at android.widget.TextView.<init>(TextView.java:447)
at android.widget.TextView.<init>(TextView.java:442)
at com.test.custom.RobotoTextView.<init>(RobotoTextView.java:16)
at android.view.LayoutInflater.createView(LayoutInflater.java:587)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
at org.robolectric.tester.android.view.RoboWindow.setContentView(RoboWindow.java:82)
at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.java:273)
at android.app.Activity.setContentView(Activity.java)
at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.java:12)
at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.java:28)
... 22 more
Caused by: java.lang.RuntimeException: no value found for RobotoMedium.ttf
at org.robolectric.shadows.Converter$EnumOrFlagConverter.findValueFor(Converter.java:375)
at org.robolectric.shadows.Converter$EnumConverter.fillTypedValue(Converter.java:343)
at org.robolectric.shadows.Converter$EnumConverter.fillTypedValue(Converter.java:336)
at org.robolectric.shadows.Converter.convertAndFill(Converter.java:148)
at org.robolectric.shadows.Converter.convertAndFill(Converter.java:50)
at org.robolectric.shadows.ShadowResources.createTypedArray(ShadowResources.java:228)
at org.robolectric.shadows.ShadowResources.attrsToTypedArray(ShadowResources.java:203)
at org.robolectric.shadows.ShadowResources.access$000(ShadowResources.java:51)
at org.robolectric.shadows.ShadowResources$ShadowTheme.obtainStyledAttributes(ShadowResources.java:460)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.robolectric.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.java:455)
at android.content.res.Resources$Theme.obtainStyledAttributes(Resources.java)
at android.widget.TextView.$$robo$$TextView_347d___constructor__(TextView.java:561)
at android.widget.TextView.<init>(TextView.java:447)
at android.widget.TextView.<init>(TextView.java:442)
at com.test.custom.RobotoTextView.<init>(RobotoTextView.java:16)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createView(LayoutInflater.java:587)
at android.view.LayoutInflater.createView(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createViewFromTag(LayoutInflater.java:687)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.rInflate(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:396)
at android.view.LayoutInflater.inflate(LayoutInflater.java)
at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:352)
at android.view.LayoutInflater.inflate(LayoutInflater.java)
at org.robolectric.tester.android.view.RoboWindow.setContentView(RoboWindow.java:82)
at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.java:273)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.robolectric.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.java:455)
at android.app.Activity.setContentView(Activity.java)
at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.java:12)
at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
... 22 more
Could you guys please point me in the right direction? I'm out of ideas.
Thanks.
I test views in the same test class with the Activity that uses them. In this case I tell Robolectric to give an instance of that Activity and from that I get an instance of the inflated view:
#Before
public void setup(){
activity = Robolectric.buildActivity(MyActivity.class).create().get();
View view = LayoutInflater.from(activity).inflate(R.layout.myView, null);
}
#Test
public void allElementsInViewProduct(){
assertNotNull(view.findViewById(R.id.view1));
assertNotNull(view.findViewById(R.id.view2));
assertNotNull(view.findViewById(R.id.view3));
}
LE: I use Robolectric 3.0 so I am not sure if this applies to you.
Problem:
This issue happens, because gradle merges project dependencies (ex: compile project(':lib-custom')) and external dependencies (ex: compile 'lib.package:name:1.1.0') in different way. After dependencies were merged app has R.java file with all resources fields (colors, ids, drawables, ...). But generated R.java file looks different after merging submodules and external dependencies.
This problem exists only with projects, which have custom views in submodules. In case of external dependencies there is another issues, which can be easily fixed. Read about dependencies types here.
For project dependencies result R.java file contains all resource identifiers, but identifiers from submodule doesn't equals to their original integer identifiers:
com.lib.custom.R.color.primary != com.main.project.R.color.primary
For external dependencies merged R.java file just a merge result of R.java files from all external dependencies
com.lib.custom.R.color.primary == com.main.project.R.color.primary
Solution:
I've found two possible solutions:
Convert your dependencies from submodule to external where possible. For example for viepager indicator has an item in maven.org repository - fr.avianey.com.viewpagerindicator:library.
But this is still not enough - you need to add related item to project.properties file to your main sourceSet. More info here
Example:
// add this dependency to your gradle file instead of project dependency
compile 'fr.avianey.com.viewpagerindicator:library:2.4.1#aar'
// add library dependencies for robolectric (now robolectric knows
// about additional libraries to load resources)
android.library.reference.1=../../../app/build/intermediates/exploded-aar/fr.avianey.com.viewpagerindicator/library/2.4.1
You can check diff for this solution here
Move all your custom views under your main app. It is not good approach to move Custom views to app only because of unit testing, but this will also fix issue with Error inflating class.
I prefer first solution but it is not possible sometimes change project dependency to external.
I am also going to report about this issue to Robolectric team.
P.S. I have project on github related to this issue.
mTestRoboActivityView = LayoutInflater.from(new Activity()).inflate(R.layout.test, null);
In this line of code you used 'new Activity()' means instance of new Activity, that not for your current Activity.
You can resolve this issue by passing instance on current Activity.
Use like this-
public class TestRoboActivityTest {
private View mTestRoboActivityView;
private Context mContext;
public TestRoboActivityTest(Context mContext){
this.mContext=mContext;
}
#Before
public void setUp() throws Exception {
mTestRoboActivityView = (LayoutInflater.from(mContext)).inflate(R.layout.test, null);
}
#After
public void tearDown() throws Exception {
mTestRoboActivityView = null;
}
#Test
public void testSanity() throws Exception {
Assert.assertNotNull(mTestRoboActivityView);
}}
I am not sure that above code working fine but use for reference, instance of current Activity.
Refer it may be help you.
You cannot inflate views in Roboelectric since it does not use the complete android framework but instead mocks out all the Android API's.
You should not use roboelectric to test actual view display behavior.
It is to be used for unit tests and just to test your business logic and not view drawing/display etc. To achieve that You can programmatically create view objects and mock out certain parts which need the android system (Use something like Mockito or Powermock).
eg of simple view testing in roboelectic:
MyCustomView view = new MyCustomView();
assertNotNull(view.setSomeNo(2);
assertTrue(2, view.getSomeNo());
Also if you want to test rendering of how your view looks or renders etc, you should use functional testing frameworks such as Espresso or Robotium which run on an actual device.

android.view.InflateException: Error inflating class fragment

I got the following error:
02-13 12:37:05.015: E/AndroidRuntime(8766): FATAL EXCEPTION: main
02-13 12:37:05.015: E/AndroidRuntime(8766): android.view.InflateException: Binary XML file line #9: Error inflating class fragment
02-13 12:37:05.015: E/AndroidRuntime(8766): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
...
02-13 12:37:05.015: E/AndroidRuntime(8766): Caused by: java.lang.IllegalArgumentException: Binary XML file line #9: Duplicate id 0x7f05005f, tag null, or parent id 0x0 with another fragment for com.handmark.pulltorefresh.extras.listfragment.PullToRefreshListFragment
02-13 12:37:05.015: E/AndroidRuntime(8766): at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:285)
02-13 12:37:05.015: E/AndroidRuntime(8766): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:676)
02-13 12:37:05.015: E/AndroidRuntime(8766): ... 27 more
I'm creating an android app with an actionbar sherlock with an horizontal swipe between the tabs. For each tab I have loaded a fragment and I have a problem in one of these.
In this fragment I have a nested fragment, which is essential for the pull-to-refresh list.
Hence, I have the following layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_people_layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment
android:id="#+id/frag_ptr_list"
android:name="com.handmark.pulltorefresh.extras.listfragment.PullToRefreshListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fastScrollEnabled="true"
android:drawSelectorOnTop="false"
android:divider="#android:color/transparent"
android:layout_margin="10dp" />
<TextView
android:id="#id/android:empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:text="#string/footer_loading_data" />
</LinearLayout>
And the following snippet of code:
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
activity = getActivity();
mPullRefreshListFragment = (PullToRefreshListFragment)
activity.getSupportFragmentManager().findFragmentById(R.id.frag_ptr_list);
....
}
The issue comes out when I'm swiping between the tabs, and when the fragment is redrawn.
Just to let you know, I'm using the Support Library v4.
fragments cannot hold other fragments.
but .....
With current versions of the Android Support package -- or native fragments on API Level 17 and higher -- you can nest fragments, by means of getChildFragmentManager(). Note that this means that you need to use the Android Support package version of fragments on API Levels 11-16, because even though there is a native version of fragments on those devices, that version does not have getChildFragmentManager().

Categories

Resources