I'm trying to include different layouts in my View depending on the parent Theme.
Following the idea:
attrs.xml
<attr name="themeLayout" format="reference" />
styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="themeLayout">#layout/layout_a</item>
</style>
<style name="AppThemeSecond" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="themeLayout">#layout/layout_b</item>
</style>
activity.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"
tools:context=".MainActivity">
<include layout="?attr/themeLayout" />
</RelativeLayout>
When I run the Code above I'll get the following Exception:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.package/com.my.package.MainActivity}: android.view.InflateException: You must specifiy a valid layout reference. The layout ID ?attr/themeLayout is not valid.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: android.view.InflateException: You must specifiy a valid layout reference. The layout ID ?attr/themeLayout is not valid.
at android.view.LayoutInflater.parseInclude(LayoutInflater.java:866)
What am I doing wrong? Is it possible to do this at all?
Note #1: I set the Theme of my MainActivity to android:theme="#style/AppTheme"
Note #2: In the Design-View of the Layout Editor everything works as expected. If I switch the Theme, the include gets updated properly.
See the following Screenshots as well:
Unfortunately this is not possible but I really like the idea. I have tracked the flow of LayoutInflater and it requieres the layout attribute to be TypedValue.TYPE_REFERENCE which means ?attr is not allowed. They even left a comment in the method to explain.
public int getAttributeResourceValue(int idx, int defaultValue) {
int t = nativeGetAttributeDataType(mParseState, idx);
// Note: don't attempt to convert any other types, because
// we want to count on aapt doing the conversion for us.
if (t == TypedValue.TYPE_REFERENCE) {
return nativeGetAttributeData(mParseState, idx);
}
return defaultValue;
}
android.content.res.XmlBlock.java:385
Basically you have done nothing wrong -- the inflation in Preview works differently which caused the confusion.
Since Lamorak explained everything in detail in his "in-depth" answer I guess it's save to say that there isn't any solution with the <include /> tag for your problem.
So following a different approach that worked in my test project:
#1 - Replace <include /> with <ViewStub />
<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"
tools:context=".MainActivity">
<ViewStub
android:id="#+id/myStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="#+id/myInflatedStub"
android:layout="?attr/themeLayout" />
</RelativeLayout>
#2 - Inflate the ViewStub
ViewStub myStub = (ViewStub) findViewById(R.id.myStub);
myStub.inflate();
Any drawbacks with this method? Well you won't see the ViewStub-Layout in your Design-Tab and using the <merge /> tag won't work.
After some research, I found this problem-"has been fixed in Android23. But bellows, exception will be thrown.
Related
I would like to create simple custom UI elements in Android like the ones from the screenshot:
The light bulb should always have the same size but the rectangle should vary in the width. One option of doing this is to use Canvas elements. But I would like to ask whether there is also an easier approach for doing this. Is it possible to maybe only do this by using XML files? I would like to use these UI elements then in the LayoutEditor like e.g. a TextView where I can adjust the widht and height either in the XML layout file or programmatically.
Any idea how I can do that in an easy way?
Update: I tried the suggested approach from Cheticamp and I have the following code inside my Fragment:
public class Test extends Fragment implements Runnable {
/*
Game variables
*/
public static final int DELAY_MILLIS = 100;
public static final int TIME_OF_A_LEVEL_IN_SECONDS = 90;
private int currentTimeLeftInTheLevel_MILLIS;
private Handler handler = new Handler();
private FragmentGameBinding binding;
private boolean viewHasBeenCreated = false;
public Test() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentGameBinding.inflate(inflater, container, false);
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
container.getContext();
viewHasBeenCreated = true;
startRound();
return binding.getRoot();
}
public void startRound () {
currentTimeLeftInTheLevel_MILLIS =TIME_OF_A_LEVEL_IN_SECONDS * 1000;
updateScreen();
handler.postDelayed(this, 1000);
}
private void updateScreen() {
binding.textViewTimeLeftValue.setText("" + currentTimeLeftInTheLevel_MILLIS/1000);
/*
IMPORTANT PART: This should create a simple custom UI element but it creates an error
*/
View view = new View(getActivity());
view.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
Drawable dr = ContextCompat.getDrawable(getActivity(),R.drawable.light_bulb_layer_list);
view.setBackground(dr);
ConstraintLayout constraintLayout = binding.constraintLayout;
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(constraintLayout);
constraintSet.connect(view.getId(),ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID,ConstraintSet.BOTTOM,0);
constraintSet.connect(view.getId(),ConstraintSet.TOP,ConstraintSet.PARENT_ID ,ConstraintSet.TOP,0);
constraintSet.connect(view.getId(),ConstraintSet.LEFT,ConstraintSet.PARENT_ID ,ConstraintSet.LEFT,0);
constraintSet.connect(view.getId(),ConstraintSet.RIGHT,ConstraintSet.PARENT_ID ,ConstraintSet.RIGHT,0);
constraintSet.setHorizontalBias(view.getId(), 0.16f);
constraintSet.setVerticalBias(view.getId(), 0.26f);
constraintSet.applyTo(constraintLayout);
}
private void countDownTime(){
currentTimeLeftInTheLevel_MILLIS = currentTimeLeftInTheLevel_MILLIS -DELAY_MILLIS;
updateScreen();
}
#Override
public void run() {
if(viewHasBeenCreated) {
countDownTime();
}
}
}
Unfortunately, this code leads to a "java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Context.isUiContext()' on a null object reference". It is thrown by the line View view = new View(getActivity());. Here is the complete error message:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.game, PID: 12176
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Context.isUiContext()' on a null object reference
at android.view.ViewConfiguration.get(ViewConfiguration.java:502)
at android.view.View.<init>(View.java:5317)
at com.example.game.Test.updateScreen(Test.java:72)
at com.example.game.Test.countDownTime(Test.java:91)
at com.example.game.Test.run(Test.java:97)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Any idea what the problem is? Without the custom UI element the Fragment works fine.
Use a TextView. The light bulb can be a left compound drawable. Set the background to a rounded rectangle shape drawable. This can all be specified in XML. See TextView.
This can also be accomplished with a LayerList drawable if text is not wanted. (The TextView solution also works without text - just set the text to "" or null.)
<layer-list>
<item>
<shape android:shape="rectangle">
<corners android:radius="5dp" />
<solid android:color="#FF9800" />
</shape>
</item>
<item
android:drawable="#drawable/ic_baseline_lightbulb_24"
android:width="48dp"
android:height="48dp"
android:gravity="left|center_vertical" />
</layer-list>
The layer list is set as a background to a simple View.
<View
android:layout_width="250dp"
android:layout_height="56dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:background="#drawable/light_bulb_layer_list" />
To create the View in code:
View view = new View(context);
view.setLayoutParams(new ViewGroup.LayoutParams(width, height));
Drawable dr = ContextCompat.getDrawable(context,R.drawable.light_bulb_layer_list)
view.setBackground(dr);
Sure thing.
In this case a simple xml file like so would suffice. Let's name it something.xml inside the layout folder.
<LinearLayout ...>
<ImageView ...>
</LinearLayout>
In another layout xml file you may just:
<ConstraintLayout ...>
<include android:id="#+id/something"" layout="#layout/something" android:layout_width="70dp">
</ConstraintLayout>
See Reusing layouts
If you'd like to get a children you can always get them by using findViewById on your Activity or Fragment. If you're using Databinding or Viewbinding it just gets better: They'll appear as fields in the XBinding class that was generated out of the XML file
Hi VanessaF, going a little bit further with the clarifications you asked in the comments:
<include />
The <include /> tag is a special XML tag that we can use in our Android XML layout files to indicate that where we placed the <include/> we'd like it to be replaced by some other XML determined via the layout attribute inside the <include /> tag.
Here's an example:
Considering layout/example.xml
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello!"/>
And considering layout/parent.xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button .../>
<include layout="#layout/example"/>
<ImageView android:drawable="#drawable/ic_send"/>
</LinearLayout>
Whenever I use R.layout.parent somewhere (for example in setContent from the Activity the view that would get generated would be as follows:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button .../>
<!-- PLEASE NOTICE THAT <include/> IS GONE -->
<!-- AND HAS BEEN REPLACED WITH THE CONTENTS the specified layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello!"/>
<ImageView android:drawable="#drawable/ic_send"/>
</LinearLayout>
Effectively re-using the layout without writing a full-blown custom view.
Notice: All attributes you specify inside the <include/> tag will effectively override the others specified inside the layout file. Let me illustrate this using an example:
Consider again layout/example.xml. Notice that this time the TextView will shrink to the size of the text both in height and width.
<TextView
android:text="Hello!"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
And consider the parent: layout/parent.xml. Notice that I am setting the attributes android:layout_width and android:layout_height.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
layout="#layout/example"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
In this case, when Android replaces <include/> for the contents of #layout/example it will also set android:layout_width="match_parent" and android:layout_height="match_parent" because they were specified on the <include/> tag effectively ignoring the original attributes set inside layout/example.xml (which were set to "wrap_content")
I suggest reading Custom View Components from the official Android documentation. In fact, you should become very familiar with this documentation for everything you do with Android apps.
I am using a simple TextView in my activity and want to make it appear in a custom font 'Black Chancery'. I have put the blkchcry.ttf file at location app>src>main>assets>fonts>blkchcry.ttf. But, the android studio can't find that font. Here's my AboutusActivity.java code
public class AboutusActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aboutus);
TextView tx = (TextView)findViewById(R.id.title);
Typeface custom_font = Typeface.createFromAsset(getAssets(), "fonts/blkchcry.ttf");
tx.setTypeface(custom_font);
}
}
and following is the activity_aboutus.xml
<?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"
tools:context=".AboutusActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="About Rathi Classes"
android:textSize="20sp"
android:layout_margin="10dp"
android:gravity="center_horizontal"/>
<TextView
android:layout_below="#+id/title"
android:id="#+id/description"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/about_text"
android:textSize="20sp"
android:layout_margin="10dp" />
</RelativeLayout>
and here is the logcat
Process: net.softglobe.rathiclasses, PID: 8894
java.lang.RuntimeException: Unable to start activity ComponentInfo{net.softglobe.rathiclasses/net.softglobe.rathiclasses.AboutusActivity}: java.lang.RuntimeException: Font asset not found fonts/blkchcry.ttf
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.RuntimeException: Font asset not found fonts/blkchcry.ttf
at android.graphics.Typeface.createFromAsset(Typeface.java:206)
at net.softglobe.rathiclasses.AboutusActivity.onCreate(AboutusActivity.java:17)
at android.app.Activity.performCreate(Activity.java:6679)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
I have tried cleaning the project but it failed to resolve the problem. Please help.
Change the location your blkchcry.tttf
from
app>src>main>assets>fonts>blkchcry.ttf.
to
app>src>main>res>font>blkchry.tff
And here's the fun part,
you need to create a custom font file inside the same folder.
Name it as my_font.xml
That's called Creating a Font Family
If you’re using multiple versions of the same font, then you may want to group them together into a font family. A font family is essentially a dedicated XML file where you define each version of the font, along with its associated style and weight attributes.
Here's a demo font file
[Update] which you can simply paste coz I updated the contents.
<?xml version="1.0" encoding="utf-8"?>
<font-family 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">
<font
android:font="#font/blkchry"
android:fontStyle="normal"
android:fontWeight="400"
app:font="#font/blkchry"
app:fontStyle="normal"
app:fontWeight="400"
tools:ignore="UnusedAttribute" />
</font-family>
Because getAssets() will look for an .xml file, not .tff even though you mentioned .tff file in your code.
Paste Font here like this and also make your font name in small case
:-
app > src > main > assets > fonts > blkchry.tff
set Font in java File like this :-
public class AboutusActivity extends Activity {
Context mContext;
Typeface fontblkchry;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
setContentView(R.layout.activity_about_us);
fontblkchry = Typeface.createFromAsset(mContext.getAssets(), "fonts/blkchry.ttf");
textview1.setTypeface(fontblkchry);
}
}
Change your location:
from
app>src>main>assets>fonts>blkchcry.ttf.
to
app>src>main>res>font>blkchry.tff
then change your typeface:
Typeface typeface = getResources().getFont(R.font.blkchcry); textView.setTypeface(typeface);
See more details: https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml
In my case, I was adding a font with Capital Letters and some symbols like -(hyphen).
Try renaming the fonts.
So, just make all letters small, replace hyphen with underscore _
I have an AppWidget that is producing this error:
W/AppWidgetHostView: updateAppWidget couldn't find any view, using
error view
android.view.InflateException: Binary XML file line #2: Failed to
resolve attribute at index 1: TypedValue{t=0x2/d=0x7f01009a a=-1}
Caused by: java.lang.UnsupportedOperationException: Failed to resolve attribute
at index 1: TypedValue{t=0x2/d=0x7f01009a a=-1}
I can tell the error is being caused by inflation of a layout, and I can pin it to the creation of a new RemoteViews in my RemoteViewsService.RemoteViewsFactory subclass' getViewAt() method:
#Override
public RemoteViews getViewAt(int position) {
[…]
final RemoteViews views = new RemoteViews(getPackageName(),
R.layout.appwidget_list_item);
[…]
return views;
}
Commenting this line out removes this particular error, and yet I cannot figure out what is wrong with the layout file it is referencing.
Layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_view"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="?listPreferredItemHeight">
<TextView
android:id="#+id/item_name"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center_vertical"
android:paddingEnd="?listPreferredItemPaddingRight"
android:paddingStart="?listPreferredItemPaddingLeft"/>
</LinearLayout>
The error is cause by using using theme attributes (such as ?listPreferredItemHeight) in an AppWidget layout, which isn't possible. These are the "unresolved attribute(s)" the error is referring to.
I am trying to create an Activity that extends AppCompatActivity and has two fragments inside of it (one below another - just by using a LinearLayout). I would like the first fragment to extend the PreferenceFragmentCompat class from the support-v7 library.
I followed Google's short example regarding PreferenceFragmentCompat as shown at https://developer.android.com/reference/android/support/v7/preference/PreferenceFragmentCompat.html.
Here is my current code:
GroupDetailsActivity.java
public class GroupDetailsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_group_details);
GroupDetailsPrefFragment prefFragment = GroupDetailsPrefFragment.newInstance();
GroupDetailsMembersFragment membersFragment = GroupDetailsMembersFragment.newInstance();
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction()
.add(R.id.flPrefFragment, prefFragment, GroupDetailsPrefFragment.TAG)
.add(R.id.flMembersFragment, membersFragment, GroupDetailsMembersFragment.TAG)
.commit();
}
}
GroupDetailsPrefFragment .java - The problematic fragment
public class GroupDetailsPrefFragment extends PreferenceFragmentCompat {
public static final String TAG = "GroupDetailsPrefFragment";
#Override
public void onCreatePreferences(Bundle bundle, String s) {
setPreferencesFromResource(R.xml.group_details_preferences, s);
}
public static GroupDetailsPrefFragment newInstance() {
GroupDetailsPrefFragment fragment = new GroupDetailsPrefFragment();
return fragment;
}
}
GroupDetailsMembersFragment.java - Completely empty for now..
public class GroupDetailsMembersFragment extends Fragment {
public static final String TAG = "GroupDetailsMembersFragment";
public static GroupDetailsMembersFragment newInstance() {
GroupDetailsMembersFragment fragment = new GroupDetailsMembersFragment();
return fragment;
}
}
activity_group_details.xml - Activity's layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/flPrefFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/flMembersFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
group_details_preferences.xml - The preference XML file
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:title="#string/remove_me"
android:key="#string/pref_key_settings_remove_me"/>
<Preference
android:title="#string/delete_group"
android:key="#string/pref_key_settings_delete_group"/>
</PreferenceScreen>
Trying to compile and run the code above lead me into a few errors, the first one was regarding a preference theme that was not set. I have quickly scanned the internet and found you need to add the following line into your Activity's theme : <item name="preferenceTheme">#style/PreferenceThemeOverlay.v14.Material</item>
To do so, I was needed to add the support-v14 library to gradle!
Trying to run the code again, lead me to another error, which is the reason I am posting this, and so far I didn't find any way to solve this issue. Here is the crash log :
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.cochat.android/com.cochat.android.ui.groups.details.GroupDetailsActivity}: java.lang.RuntimeException: Content has view with id attribute 'android.R.id.list_container' that is not a ViewGroup class
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2305)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
at android.app.ActivityThread.access$900(ActivityThread.java:161)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5356)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: Content has view with id attribute 'android.R.id.list_container' that is not a ViewGroup class
at android.support.v7.preference.PreferenceFragmentCompat.onCreateView(PreferenceFragmentCompat.java:269)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2184)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1298)
at android.support.v4.app.FragmentManagerImpl.moveFragmentsToInvisible(FragmentManager.java:2323)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2136)
at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2092)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1998)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:388)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:607)
at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:181)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1189)
at android.app.Activity.performStart(Activity.java:5441)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
at android.app.ActivityThread.access$900(ActivityThread.java:161)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5356)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
at dalvik.system.NativeStart.main(Native Method)
Been stuck on this for a while now, tried looking up different posts on stackoverflow or other websites, seen some solutions, but for some reason none of them managed to solve my problem.
Edit:
My gradle file contains the following:
compileSdkVersion 25
buildToolsVersion '25.0.2'
...
compile 'com.android.support:preference-v7:25.1.0'
compile 'com.android.support:preference-v14:25.1.0'
Update Jan 02 '17
I've been looking into the source code of PreferenceFragmentCompat and seen it is trying to load the following layout: R.layout.preference_list_fragment.
In the onCreateView() method of the class, it is inflating the layout, and trying to look for the id android.R.id.list_container.
The problem is that there is no such id within the layout.
Here is a code snippet from the PreferenceFragmentCompat:
final View view = themedInflater.inflate(mLayoutResId, container, false);
final View rawListContainer = view.findViewById(AndroidResources.ANDROID_R_LIST_CONTAINER);
if (!(rawListContainer instanceof ViewGroup)) {
throw new RuntimeException("Content has view with id attribute "
+ "'android.R.id.list_container' that is not a ViewGroup class");
}
While
private int mLayoutResId = R.layout.preference_list_fragment;
Still looking for a solution, thanks!
I got past this using the following bugfix:
https://github.com/Gericop/Android-Support-Preference-V7-Fix
Simple 3 step process is to update the app's build.gradle,
Remove:
compile 'com.android.support:preference-v7:25.0.1'
compile 'com.android.support:preference-v14:25.0.1'
Add
compile 'com.takisoft.fix:preference-v7:25.0.1.0'
Then update your app's theme for preferences to use PreferenceFixTheme
(You're already using PreferenceFragmentCompat so good to go).
UPDATE:
On further investigation, with api 25.1.0, AppCompat worked fine once I realized the very strict restrictions on the style for Preferences.
I found this resource very helpful in getting everything set up nicely:
According to this article:
Note that Google changed the needed id from R.id.list_container (in
revision 23.4.0) to android.R.id.list_container (in revision 24.0.0).
Android Studio says the new id requires API 24, but it also works on
older APIs.
ViewGroup in your layout file (activity_group_details.xml) should have id "#android:id/list_container”. to make it work. It can look like this:
<FrameLayout
android:id="#android:id/list_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/flMembersFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
And you have to use this id for your transaction too, note that the other fragment of yours can use any Id for container, only pref is 'special'
So I have found a work around for this, might not be the best, but it is the only thing I have managed to get working! It seems like a problem/bug with the support library..
I have copied the original PreferenceFragmentCompat to a local class, and made minor changed to it. I have replace the following line
private int mLayoutResId = android.support.v7.preference.R.layout.preference_list_fragment;
with
private int mLayoutResId = R.layout.preference_fragment_compat_container;
which is a layout I have made, that it very simple and only contains a container for the list. Here is the layout code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/list_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
Doing the above will allow you to use PreferenceFragmentCompat with the specific gradle settings above (see original post) without any problems.
The down side is that upgrading the support libraries will not upgrade your PreferenceFragmentCompat since it is copied of course. You will need to keep track of the support libraries, and when ever the problem is fixed, you may delete the copied class and use the original one.
If you have any other solutions or ideas please share!
I think you just need to use the support PreferenceScreen and Preferences:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v7.preference.Preference
android:title="#string/remove_me"
android:key="#string/pref_key_settings_remove_me"/>
<android.support.v7.preference.Preference
android:title="#string/delete_group"
android:key="#string/pref_key_settings_delete_group"/>
</android.support.v7.preference.PreferenceScreen>
Checked out my answer here https://stackoverflow.com/a/53560798/1247248
you need a layout resource with that id
Adding this line to your AppTheme in the styles.xml file should do the trick:
<item name="preferenceTheme">#style/PreferenceThemeOverlay</item>
I have an app that is about a year old, is on the Play store in beta, has gone through dozens of revisions. All of a sudden I'm getting an error:
Could not find a method onClick_Foo(View) in the activity class
android.view.ContextThemeWrapper for onClick handler on view class
android.widget.Button with id 'Foo_Button'
I'm getting this error on every one of the 7 buttons defined in my XML. Since yesterday I've updating appcompat-v7 from 21.0.3 to 22.0.0 but also upgraded my testing device from KitKat to Lollipop for the first time.
I've double-checked spellings, capitalizations, none of the usual suspects explains this. Here's a sample of the relevant code. Let me know if you feel more would be helpful. (The activity has 915 lines of code and the xml 186, so don't ask for the whole thing). Testing on a Verizon Note 4 running Lollipop 5.0.1
activity_pick.xml:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:theme="#style/AppTheme"
tools:context="com.myapp.Pick"
android:layout_height="match_parent"
android:layout_width="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/Ratings_Button"
android:textSize="16dp"
android:text="#string/Pick_Ratings_Button"
android:onClick="onClick_Ratings"
android:background="#android:drawable/btn_default"/>
</LinearLayout>
</ScrollView>
Pick.java:
public class Pick_Restaurant extends ActionBarActivity {
public void onClick_Ratings (View v) {
Intent intent = new Intent(mContext, Ratings.class);
startActivityForResult(intent,RATINGS);
}
}
build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
minSdkVersion 15
targetSdkVersion 22
versionCode 59
versionName "0.6.4"
}
...
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:22.0.0'
compile 'com.google.android.gms:play-services:7.0.0'
compile files('libs/mobileservices-1.1.5.jar')
}
Full Error on Log:
04-08 17:06:40.578 3508-3508/com.myapp.debug E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.myapp.debug, PID: 3508
java.lang.IllegalStateException: Could not find a method onClick_Ratings(View) in the activity class android.view.ContextThemeWrapper for onClick handler on view class android.widget.Button with id 'Ratings_Button'
at android.view.View$1.onClick(View.java:4234)
at android.view.View.performClick(View.java:5191)
at android.view.View$PerformClick.run(View.java:20916)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5974)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)
Caused by: java.lang.NoSuchMethodException: onClick_Ratings [class android.view.View]
at java.lang.Class.getMethod(Class.java:665)
at android.view.View$1.onClick(View.java:4227)
at android.view.View.performClick(View.java:5191)
at android.view.View$PerformClick.run(View.java:20916)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5974)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)
It looks like this is a new issue with Android 5.0.
From this anwer, removing the Theme from the layout xml fixed this issue for them.
So in your case, remove the theme from your layout:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!--android:theme="#style/AppTheme"--> <!-- Remove this -->
<!--................-->
</ScrollView>
And add the theme in the AndroidManifest.xml instead:
android:theme="#android:style/AppTheme"
I have just answered a similar question here
Basically, since Android 5.0 individual views can be themed.
To facilitate this, a ContextThemeWrapper is used to modify the underlying theme assigned to the Activity and assigned as the Context of the View. Since this Context is not your Activity anymore (the Activity has to be separate because it still has to return the original theme) the callbacks don't exist and you get the error you see.
If you don't really want to theme individual views the obvious solution is to not do so and theme the activity instead, as already suggested.
If you do indeed want to theme individual views, it appears that the android:onClick attribute cannot be used and you will have to fall back to manually assign an OnClickListener.
The question is, why did this work pre Lollipop? I can only speculate that because the functionality to theme individual views didn't exist, applying a theme attribute to a view would just change the default theme on the Activity as well.
Such things usually happens when you declare onClick in xml like you did:
android:onClick="onClick_Ratings"
Just make sure you are using this layout in that activity. Because the exception is clearly saying that your activity don't have the corresponding method which you did show you have:
public void onClick_Ratings (View v) {
Intent intent = new Intent(mContext, Ratings.class);
startActivityForResult(intent,RATINGS);
}
Also I guess you should declare the activity in your xml like:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".SendMessageActivity">
And actually log says:
Could not find a method onClick_Ratings(View) in the activity class
android.view.ContextThemeWrapper
there is something wrong since android.view.ContextThemeWrapper is not an Activity and not the activity from your xml com.myapp.Pick (I assume Pick is an activity and not the fragment). Maybe try to clean up the project, ivalidate caches and restart.
If nothing helps I suggest you to return back to previuos version of support lib you'd mentioned OR to set onClickListener in code instead of xml.
Removing android:theme works. But this is caused because using android:onclick in xml. If you use onClick in Java file, you can still use android:theme.
According to your code,
activity_pick.xml [Remove onclick here]
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/Ratings_Button"
android:textSize="16dp"
android:text="#string/Pick_Ratings_Button"
android:background="#android:drawable/btn_default" />
Go to your Java File, that is, pick.java in your case:
final Button button = (Button) findViewById(R.id.Ratings_Button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent activityChangeIntent = new Intent(CurrentActivity.this, SecondActivity.class);
SplashScreen.this.startActivity(activityChangeIntent);
}
});
Experienced the same error, app has stopped working, when material button was clicked programmatically helped me. Check it out :)