Inflation Exception in XML of view for inner nested class - java

I have some code that works perfect with no errors if the view class (JavaCameraImageView) is inflated in the XML layout as an external class, it also works if the class is included in the same .java file external to the main activity class. however when I tried to use the JavaCameraImageView class as an inner class inside of the main class I get the errors and logcat output shown here. how do I get this to work as nested inner class?
Logcat result
01-14 15:17:37.486: E/AndroidRuntime(8347): FATAL EXCEPTION: main
01-14 15:17:37.486: E/AndroidRuntime(8347): java.lang.RuntimeException:
Unable to start activity ComponentInfo{com.group.cam/com.group.cam.MainActivity}:
android.view.InflateException: Binary XML file line #28: Error inflating class
com.group.cam.MainActivity$JavaCameraImageView
XML layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:opencv="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity" >
<FrameLayout
android:id="#+id/frameLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<view
class="com.group.cam.MainActivity$JavaCameraImageView"
android:id="#+id/camera_surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
</LinearLayout>
onCreate method of class MainActivity
#Override
public void onCreate(Bundle savedInstanceState) {
if (!OpenCVLoader.initDebug()) {
// Handle initialization error
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
frameLayoutOne = (FrameLayout) findViewById(R.id.frameLayout1);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mOpenCvCameraView = (JavaCameraImageView) findViewById(R.id.camera_surface_view);
mOpenCvCameraView.setCvCameraViewListener(this);
mOpenCvCameraView.setMaxFrameSize(reducedDimensions.width, reducedDimensions.height);
} // end on create
class JavaCameraImageView that nested as an inner class inside of MainActivity class
public class JavaCameraImageView extends JavaCameraView {
public JavaCameraImageView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
}
EDIT: solution to this problem, the JavaCameraImageView class must be made static for it to work as an inner class in this situation
public static class JavaCameraImageView extends JavaCameraView {
public JavaCameraImageView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
}

error is because of this
<view
class="com.group.cam.MainActivity$JavaCameraImageView"
android:id="#+id/camera_surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
you should make your inner class static.
The thing is static inner classes are nothing but a class which is accessible via it's outer class.
This class does not belong to the instance of the outer class but the outer class itself so to create an object of static inner class all you need to do is:
new Outer.Inner();
Outer.Inner becomes it's qualified name
But if your inner class is not static then it belongs to the instance of the outer class so to create an object you need to write:
new Outer().new Inner();
This class is not accessible view Outer class but via Object of outer class.
That is why when you use it in manifest this class is not accessible via your class name.

Related

Android Custom View's constructor is executed twice

I have faced an issue after creating custom view class in android. The issue is simply, when I create an object of the custom view, its constructor is executed multiple times.
Code of the main Activity Class
public class MainActivity2 extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
CustomView customView = new CustomView(this, null);
}
}
Code of the customView
package com.example.myapplication;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
public class CustomView extends View {
public CustomView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
System.out.println("Custom View is executed");
}
}
Code of main Activity's xml layout file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="4"
tools:context=".MainActivity2">
<com.example.myapplication.CustomView
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.myapplication.CustomView>
</androidx.constraintlayout.widget.ConstraintLayout>
The expected result is: the constructor of the view is executed one time
Actual Result: the constructor of the view is executed two times!
You can put a breakpoint in the constructor to examine the call stack and to learn where it is called exactly.
The first invocation comes from setContentView when the layout containing your custom view is inflated.
The second invocation is your explicit constructor call new CustomView(...) in your activity code.

Cant call method of custom ConstraintLayout class?

I want to make a custom ConstraintLayout so I can trigger some functions from the activity where its initialized.
I have the following code:
First initialized my custom view in layout:
<package.com.app.Main.LavadasView
android:id="#+id/main_autolavados_lavadas_lavadas_view"
android:layout_width="0dp"
android:layout_height="25dp"
...
/>
This is my custom class LavadasView, constraint layout initialized from another XML file:
Java class
public class LavadasView extends ConstraintLayout {
public LavadasView(Context context,AttributeSet attrs) {
super(context);
//Inflate view from XML layout file
LayoutInflater inflater =(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.lavadas_view, this);
}
public void resetView(){
//Some ui updates
}
}
LavadasView xml file, just a normal constraint layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.constraint.ConstraintLayout>
And in my Activity I get the instance with findViewByIdmehtod, then I want to call the resetView function and that gives me a null pointer exception related to LavadasView:
LavadasView lavadasView = (LavadasView) findViewById(R.id.main_autolavados_lavadas_lavadas_view);
//Call this method later on
lavadasView.resetView();
SO what am I doing wrong? I've looked up and thats the correct way to get layout instance isnt?
Thanks.
The problem is with the constructor of your LavadasView. When your Activity is inflated it will call the LavadasView(Context context, AttributeSet attrs) constructor on you custom layout. In this constructor you need to call the super(context, attrs) for the ConstraintLayout to be properly inflated, but you're only calling super(context) which is why you get the NullPointerException.

How do I link a View class to the XML screen?

I am still learning Java and how to use Eclipse but I have a XML main activity file (the graphical layout) and a Java file named Mainscreen that extends Activity.
Inside the Mainscreen file I have a Class named myView which extends View and I can get it to display on the device screen by calling setContentView(new MyView(this)); from the Mainscreen onCreate method. How do I make it so I can have the MyView be a view within the XML file?
I can also change it to setContentView(R.layout.activity_main_screen);and then it sets it to what the XML file is but how do I have it so both are displayed.
I want it to display the screen as if it was following the setContentView(R.layout.activity_main_screen); layout but then also have the MyView displayed as well inside a seperate View on the screen. I have tried setting it as setContentView(R.id.view1); but if I am being completely honest I am not 100% sure what I am doing as I am still learning.
Can someone please point me in the right direction or help me out? I have been Googling trying to figure this out and I'm a little lost.
Thanks
EDIT: added code below
XML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainScreen" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:contentDescription="#string/hello_world"
android:src="#drawable/title_plate" />
<View
android:id="#+id/view1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/imageView1"
android:layout_centerHorizontal="true" />
</RelativeLayout>
The start of the MyView class
public class MyView extends View {
public MyView(Context context) {
super(context);
//setContentView(R.id.view1);
setContentView(R.layout.activity_main_screen);
The onCreate for the main file itself
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main_screen);
setContentView(new MyView(this));
//View circleView = (View)findViewById(R.id.view1);
//circleView = (new MyView(this));
//circleView = findViewById(R.id.view1);
}
I won't post all the other stuff the file contains as it would seem pretty pointless as it is just code to do what I want it to do.
Take this Class as your view class
package com.example.utils.views;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.Button;
public class FontButton extends Button {
public static Typeface FONT_NAME;
public FontButton(Context context) {
super(context);
if (FONT_NAME == null)
FONT_NAME = Typeface.createFromAsset(context.getAssets(),
"fonts/Signika-Regular.ttf");
this.setTypeface(FONT_NAME);
}
public FontButton(Context context, AttributeSet attrs) {
super(context, attrs);
if (FONT_NAME == null)
FONT_NAME = Typeface.createFromAsset(context.getAssets(),
"fonts/Signika-Regular.ttf");
this.setTypeface(FONT_NAME);
}
public FontButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (FONT_NAME == null)
FONT_NAME = Typeface.createFromAsset(context.getAssets(),
"fonts/Signika-Regular.ttf");
this.setTypeface(FONT_NAME);
}
}
**Now in the Xml file**
<com.example.utils.views.FontButton
android:id="#+id/register_user_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="17sp"
android:background="#drawable/enter_pin"
android:onClick="#string/countryCodeClick"
android:text="#string/default_country_code" />
The XML view is a description of a class hierarchy. Each object in the XML represents a java class that inherits from View. The instances that contain other class inherit from a subclass, ViewGroup.
When you make a call like this: myActivity.setContentView(R.layout.activity_main_screen);
What you are in effect doing is instantiating all of the objects defined in the view and associating them with your Activity. You can use your custom View subclasses in the XML by supplying the full package name (e.g. com.myapp.MyViewSubclass) in the XML definition. Here is a concrete example:
<com.myapp.MyViewSubclass
android:id="#+id/myView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Now, within the java code, if you wanted to access this view, after calling myActivity.setContentView you would do something like this:
MyViewSubclass instance = (MyViewSubclass)myActivity.findViewById(R.id.myView1);
So R.java is a file that is created automatically by parsing all your XML files. R.id.myView1 is an integer that resolves to the item inside your XML file, and it will reference the object that you loaded once you load it using setContentView.

Restrict MapView area on OSMdroid

I'm trying to restrict the map view for OSM given the 4 points to act as corers.
In reference to this question, I am also trying to use the BoundedMapView.java (got from this website) to help me with this.
This is my activity codes:
public class POfflineMapView extends Activity implements LocationListener, MapViewConstants{
private BoundedMapView myOpenMapView;
//... removed unreleated variables
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mResourceProxy = new DefaultResourceProxyImpl(getApplicationContext());
setContentView(R.layout.offline_map_activity);
myOpenMapView = (BoundedMapView) findViewById(R.id.openmapview);
myOpenMapView.getTileProvider().clearTileCache();
//removed unlreleated codes
BoundingBoxE6 bbox = new BoundingBoxE6(north,east,south,west);
myOpenMapView.setScrollableAreaLimit(bbox);
}
}
This is my xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<entity.BoundedMapView
android:id="#+id/openmapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
My LogCat shows this error:
12-28 17:24:11.830: E/AndroidRuntime(14459): Caused by: java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
I'm unsure why I am still getting this error; the BoundedMapView is extended from the MapView class, why is it still having an error for the Constructor?
Kindly enlighten if I do not seem to be interpreting this error correctly, thanks!
It's because when you create a BoundedMapView in xml code, it calls this constructor, which is missing:
public BoundedMapView(final Context context, final AttributeSet attrs) {
super(context, 256, new DefaultResourceProxyImpl(context), null, null, attrs);
}

runtime InflateException when trying to use a Custom View in xml layout

I've been reading a lot of similar questions to try and find the solution for this but with no luck.
MainActivity.java
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.game);
}
game.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<View
android:id="#+id/adView"
android:background="#drawable/ad"
android:layout_width="320dp"
android:layout_height="50dp"
/>
<my.package.MainGamePanel
android:id="#+id/gameView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/> </RelativeLayout>
MainGamePanel.java
public class MainGamePanel extends SurfaceView implements SurfaceHolder.Callback {
private MainThread thread;
public MainGamePanel(Context context, AttributeSet a) {
super(context, a);
View.inflate(context, R.layout.game, null);
onFinishInflate();
thread = new MainThread(getHolder(), this);
setFocusable(true);
thread.setRunning(true);
etc. etc.
And then outside the MainGamePanel constructor is the function:
#Override
protected void onFinishInflate() {
getHolder().addCallback(this);
}
There is also a MainThread.java file but I don't think that is the problem.
This is the runtime exception:
java.lang.RuntimeException: Unable to start activity ComponentInfo{my.package/my.package.MainActivity}: android.view.InflateException: Binary XML file line #13: Error inflating class my.package.MainGamePanel
If I change the setContentView in MainActivity to setContentView(new MainGamePanel(this)) and remove the AttributeSet parameter from the constructor, and delete the View.Inflate(context, R.layout.game, null); , then it works, but I want to figure out how to use the custom view in the xml file.
it looks like you are circularly inflating layouts. you setContentView on R.layout.game, which contains a MainGamePanel, which inflates R.layout.game, which contains a MainGamePanel, etc.
you should take the View.inflate line out of the onCreate method. It's not doing anything anyway, as far as I can see. you also shouldn't explicitly call onFinishInflate. That will be called automatically when the inflation of the MainGamePanel instance is actually finished.

Categories

Resources