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

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.

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.

Android: Cant replace fragment inside activity with another fragment?

I'm new to android development and having some issues with replacing a fragment with another fragment.
In my MainFragment.java, the first thing I do in onCreate is check for internet connectivity, and if there is not, I replace that fragment with the InternetCheckFragment. However, in InternetCheckFragment.java, when I try to inflate my check_internet.xml, the app closes, but there is no error.
activity_main.xml:
<fragment 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:id="#+id/main_browse_fragment"
android:name="com.ui.MainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.ui.MainActivity"
tools:deviceIds="tv"
tools:ignore="MergeRootFrame" />
MainActivity.java:
public class MainActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
MainFragment.java:
public class MainFragment extends VerticalGridFragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (isConnectedToInternet() == true)
{
// DO stuff
}
else
{
showInternetError();
}
}
public void showInternetError()
{
getFragmentManager().beginTransaction().replace(R.id.show_internet_error , new InternetCheckFragment())
.commit();
}
....
}
InternetCheckFragment.java:
public class InternetCheckFragment extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
// Defines the xml file for the fragment
return inflater.inflate(R.layout.check_internet, parent, false);
}
}
check_internet.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/show_internet_error"
android:background="#color/black_transparent">
<Button android:id="#+id/btn_retry"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="RETRY"
android:layout_centerInParent="true"/>
</RelativeLayout>
However, I'm getting the error No view found for id.
I'm sure I'm not setting something correctly? Can someone point me in the right direction?
Thanks!
You are inflating a Fragment in a Fragment using the Fragment's FragmentManager.
This FragmentManager cannot handle this.
Try using the SupportFragmentManager with AppCompatActivity.getSupportFragmentManager() and the support Fragments from android.support.v4.app.Fragment
Ugh!..it was a stupid mistake, I replaced R.id.show_internet_error within getFragmentManager().beginTransaction().replace(R.id.show_internet_error , new InternetCheckFragment()).commit(); with R.id.main_browse_fragment and now it works.

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.

Inflate custom android widget

I know there are dozens similar post, but it looks to me everything is correct here:
The custom widget:
public class DoubleTextItem extends LinearLayout {
private TextView txtMain;
private TextView txtDescription;
public DoubleTextItem(Context context) {
super(context);
}
public DoubleTextItem(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
((Activity)getContext()).getLayoutInflater().inflate(R.layout.widget_double_text_item, this);
setupViewItems();
}
private void setupViewItems() {
txtMain = (TextView) findViewById(R.id.txtMain);
txtDescription = (TextView) findViewById(R.id.txtDecription);
}
public void setDescription(String text) {
txtDescription.setText(text);
}
}
The custom widget layout xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/txtMain"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txtDecription"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
ANd here inside an activity function i get a casting error,
LayoutInflater inflater = LayoutInflater.from(this);
DoubleTextItem item = (DoubleTextItem) inflater.inflate(R.layout.widget_double_text_item, layout);
item.setText(som-txt);
item.setDescription("#"+athlete.getString("position"));
Here, the root View is a LinearLayout but you try to cast it your custom class:
DoubleTextItem item = (DoubleTextItem) inflater.inflate(R.layout.widget_double_text_item, layout);
The standard advice is:
All DoubleTextItems are LinearLayouts, but not all LinearLayouts are DoubleTextItems.
Meaning you cannot downcast objects from a LinearLayout to a DoubleTextItem, there are too many assumptions and Java won't let you do it.
If you want a DoubleTextItem in your layout you need to use:
<your.package.name.DoubleTextItem
... />
(Also, calling inflate inside onFinishInflate() seems a little silly especially since you don't save the inflated item... If you want to inflate a different layout, don't inflate the first one.)
Overall it looks like you are trying to recreate the now deprecated TwoLineListItem, perhaps you can learn some pointers from it's source code (or just use the TwoLineListItem.)

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);
}

Categories

Resources