This error is already looking for it and all the solutions do not work for me, I do not understand what the problem is: Binary XML file line # 17: You must supply to layout_height attribute.
I summarize, I have a BaseActivity class where I have a toolbar and I generate the code of a menu with "onCreateOptionsMenu". The toolbar is for all the activities, so in my BaseActivity I start my toolbar (but depending on a parameter of the child class) Why ?, Why the toolbar I include it in the views ... and where I have an expandable list , I included it in the "header" file and I do not start it in BaseActivity but in the daughter activity itself after listViewMyCoursesBlocks.addHeaderView (header);
Finally, in this activity of the expandable list, when I touch the menu, I get the error and I have no idea how to solve it.
Manifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher_saval"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.NoActionBar">
<activity android:name=".MyCoursesActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".FrontActivity"
android:configChanges="screenLayout|screenSize"/>
<activity
android:name=".LoginActivity"
android:configChanges="screenLayout|screenSize"/>
<activity android:name=".MyBlocksActivity"/>
<activity android:name=".MyClassActivity"/>
<activity
android:name=".VideoPlayerActivity"
android:screenOrientation="sensorLandscape"
android:configChanges="screenLayout|screenSize"/>
</application>
BaseActivity
public abstract class BaseActivity extends AppCompatActivity
{
protected SessionManager session;
protected final void onCreate(Bundle savedInstanceState, int layoutId, boolean initToolbar)
{
super.onCreate(savedInstanceState);
setContentView(layoutId);
if( initToolbar ){
initToolBar();
}
sesion = SessionManager.getInstance(this);
//if user is not in sesion, will redirect to frontactivity
if(!sesion.sesion())
{
finish();
}
}
public void initToolBar() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setNavigationIcon(R.drawable.appbar_back);
toolbar.setOverflowIcon(ResourcesCompat.getDrawable(getResources(), R.drawable.appbar_menu, null));
if( getSupportActionBar() != null ) {
getSupportActionBar().setDisplayShowTitleEnabled(false);
}
}
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menulateral, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
onBackPressed();
return true;
case R.id.cerrarsesion:
sesion.logout();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed()
{
if( this.getLocalClassName().equalsIgnoreCase("MyCoursesActivity") )
{
final AlertDialog dialog = new AlertDialog.Builder(this)
.setIcon(R.mipmap.ic_launcher_saval)
.setTitle("Salir")
.setMessage("¿Está seguro que desea cerrar su sesión?")
.setPositiveButton("Aceptar", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
sesion.clearSession();
finish();
}
})
.setNegativeButton("Cancelar", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// user doesn't want to logout
}
})
.show();
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(getResources().getColor(R.color.colorSavalBlue));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(getResources().getColor(R.color.colorSavalBlue));
}
else
{
super.onBackPressed();
}
}
protected Map<String, String> checkParams(Map<String, String> map){
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> pairs = it.next();
if(pairs.getValue()==null){
map.put(pairs.getKey(), "");
}
}
return map;
}
}
My second activity which generates the problem at some point:
MyBlocksActivity
public class MyBlocksActivity extends BaseActivity { private ExpandableListView listViewMyCoursesBlocks; private ExpandableListAdapter listAdapter; private Course myCourse;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState, R.layout.activity_my_blocks, false);
Intent i = getIntent();
myCourse = i.getExtras().getParcelable("myCourse");
listViewMyCoursesBlocks = (ExpandableListView) findViewById(R.id.listViewMyCoursesBlocks);
LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View header = inflater.inflate(R.layout.listexpandable_header, null);
listViewMyCoursesBlocks.addHeaderView(header);
//en super.Oncreate pasamos parametro falso ... para indicar si se carga el toolbar en BaseActivity
//o en la actual
initToolBar();
if( !myCourse.getBannerUrl().isEmpty() && myCourse.getBannerUrl() != null )
{
ImageView bannerImg = (ImageView) findViewById(R.id.bannerImg);
Picasso.with(getApplicationContext()).load(myCourse.getBannerUrl()).into(bannerImg);
}
//InitData
initData(new VolleyCallback()
{
@Override
public void onResponse(HashMap<String,List<Activity>> lHash, List<String> lDataHeader)
{
listAdapter = new ExpandableListAdapter(getApplicationContext(),lDataHeader,lHash);
listAdapter.notifyDataSetChanged();
listViewMyCoursesBlocks.setAdapter(listAdapter);
if( listAdapter.getGroupCount() == 1 ){
listViewMyCoursesBlocks.expandGroup(0);
}
}
});
listViewMyCoursesBlocks.setOnChildClickListener(new ExpandableListView.OnChildClickListener()
{
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id)
{
Activity myActivity = (Activity)parent.getExpandableListAdapter().getChild(groupPosition,childPosition);
if( myActivity.getIsBlocked() == 0 )
{
Intent i = new Intent(getApplicationContext(), MyClassActivity.class);
i.putExtra("myActivity", myActivity);
startActivity(i);
return true;
}
return false;
};
});
}
public void initData(final VolleyCallback callback)
{
final List<String> listDataHeader = new ArrayList<>();
final HashMap<String,List<Activity>> listHash = new HashMap<>();
final String url = Globals.APIACTIVIDADES_URL;
RequestQueue queue = Volley.getInstance(this).getRequestQueue();
StringRequest req = new StringRequest(Request.Method.POST, url, new Response.Listener<String>()
{
@Override
public void onResponse(String response)
{
try
{
JSONObject JSONresponse = new JSONObject(response);
if ( !JSONresponse.has("error") )
{
int actividadesArr_length = 0;
int bloquesActividadesArr_length = 0;
int bloquesArr_length = 0;
String bannerUrl = JSONresponse.getString("banner");
String bloque_nombre = "";
if ( JSONresponse.has("actividades") && JSONresponse.get("actividades") instanceof JSONArray )
{
JSONArray actividadesArr = JSONresponse.getJSONArray("actividades");
actividadesArr_length = actividadesArr.length();
bloque_nombre = "BLOQUE I";
listDataHeader.add(bloque_nombre);
List<Activity> actividades = new ArrayList<>();
for (int i = 0; i < actividadesArr_length; i++)
{
JSONObject activity = new JSONObject(actividadesArr.getString(i));
Integer id = activity.getInt("id");
String title = activity.getString("titulo");
String titlePref = activity.getString("tituloprefijo");
String teacher = activity.getString("expositores");
Integer isAccomplished = activity.getInt("cumplida");
Integer isBlocked = activity.getInt("bloqueo");
Integer hvVideo = activity.getInt("tienevideo");
String blockName = bloque_nombre;
actividades.add(new Activity(id, titlePref, title, teacher, isAccomplished, isBlocked, hvVideo, bannerUrl, blockName));
}
listHash.put(listDataHeader.get(0),actividades);
}
if ( JSONresponse.has("bloques") && JSONresponse.get("bloques") instanceof JSONArray )
{
JSONArray bloquesArr = JSONresponse.getJSONArray("bloques");
bloquesArr_length = bloquesArr.length();
int ini = 0;
if( actividadesArr_length > 0 ){
ini = 1;
}
int romanNumber = 1;
for (int i = ini; i < bloquesArr_length; i++)
{
JSONObject bloque = new JSONObject(bloquesArr.getString(i));
String titulo_bloque = bloque.getString("titulo");
bloque_nombre = "BLOQUE " + RomanNumerals.toRoman(romanNumber) + ": " + titulo_bloque;
listDataHeader.add(bloque_nombre);
List<Activity> actividades = new ArrayList<>();
if (bloque.has("actividades") && bloque.get("actividades") instanceof JSONArray)
{
JSONArray actividadesArr = bloque.getJSONArray("actividades");
bloquesActividadesArr_length = actividadesArr.length();
for (int j = 0; j < bloquesActividadesArr_length; j++)
{
JSONObject activity = new JSONObject(actividadesArr.getString(j));
Integer id = activity.getInt("id");
String title = activity.getString("titulo");
String titlePref = activity.getString("tituloprefijo");
String teacher = activity.getString("expositores");
Integer isAccomplished = activity.getInt("cumplida");
Integer isBlocked = activity.getInt("bloqueo");
Integer hvVideo = activity.getInt("tienevideo");
String blockName = bloque_nombre;
actividades.add(new Activity(id, titlePref, title, teacher, isAccomplished, isBlocked, hvVideo, bannerUrl, blockName));
} //for actividades
}
romanNumber++;
listHash.put(listDataHeader.get(i),actividades);
} // for bloques
}
}
else
{
JSONObject error = JSONresponse.getJSONObject("error");
Toast.makeText(getApplicationContext(), "Error: [" + error.getString("num") + "] " + error.getString("msg"), Toast.LENGTH_SHORT).show();
}
} catch (JSONException e)
{
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Error al recuperar sus datos", Toast.LENGTH_SHORT).show();
}
callback.onResponse(listHash, listDataHeader);
}
},
new Response.ErrorListener()
{
@Override
public void onErrorResponse(VolleyError error)
{
String message = "Error de conexión";
if( error.getMessage() != null && !error.getMessage().isEmpty() )
{
message += ": [" + error.getMessage() + "]";
}
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
})
{
@Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
HashMap<String, String> user = sesion.getUserDetails();
// get user data from session
params.put("sesion", user.get(sesion.getKEY_CODE()));
params.put("curso", myCourse.getId().toString());
return checkParams(params);
}
};
queue.add(req);
}
private static class VolleyCallback
{
void onResponse(HashMap<String,List<Activity>> listHash, List<String> listDataHeader) {
}
}
}
activity_my_blocks.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/myContent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<ExpandableListView
android:id="@+id/listViewMyCoursesBlocks"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ExpandableListView>
</RelativeLayout>
In this part in MyBlocksActivity I inflate my view "header" and then start toolbar.
View header = inflater.inflate(R.layout.listexpandable_header, null);
listViewMyCoursesBlocks.addHeaderView(header);
//en super.Oncreate pasamos parametro falso ... para indicar si se carga el toolbar en BaseActivity
//o en la actual
initToolBar();
listexpandable_header.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<include layout="@layout/toolbar" android:id="@+id/includetoolbar"/>
<RelativeLayout
android:id="@+id/myHeader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start"
android:layout_below="@+id/includetoolbar">
<ImageView
android:id="@+id/bannerImg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/myblocksheader"
android:textColor="@color/colorSavalBlue"
android:textSize="20sp"
android:padding="15dp"
android:layout_below="@+id/bannerImg"/>
</RelativeLayout>
Toolbar.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbarLayout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:gravity="top">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="58dp"
android:background="@color/colorWhite"
android:minHeight="@dimen/abc_action_bar_default_height_material"
android:theme="@style/Toolbar">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/appbar_logo"/>
</android.support.v7.widget.Toolbar>
</RelativeLayout>
Sorry if it is too full of files, I do not know why sometimes the code is cut in the editor, but it is understood I believe.
Any help? This is the error that throws me.
Error
E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Binary XML file line #17: You must supply a layout_height attribute.
at android.content.res.TypedArray.getLayoutDimension(TypedArray.java:491)
at android.view.ViewGroup$LayoutParams.setBaseAttributes(ViewGroup.java:5824)
at android.view.ViewGroup$MarginLayoutParams.<init>(ViewGroup.java:5992)
at android.widget.FrameLayout$LayoutParams.<init>(FrameLayout.java:610)
at android.widget.FrameLayout.generateLayoutParams(FrameLayout.java:554)
at android.widget.FrameLayout.generateLayoutParams(FrameLayout.java:56)
at android.view.LayoutInflater.inflate(LayoutInflater.java:480)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.support.v7.view.menu.MenuAdapter.getView(MenuAdapter.java:93)
at android.support.v7.view.menu.MenuPopup.measureIndividualMenuWidth(MenuPopup.java:160)
at android.support.v7.view.menu.StandardMenuPopup.tryShow(StandardMenuPopup.java:153)
at android.support.v7.view.menu.StandardMenuPopup.show(StandardMenuPopup.java:187)
at android.support.v7.view.menu.MenuPopupHelper.showPopup(MenuPopupHelper.java:290)
at android.support.v7.view.menu.MenuPopupHelper.tryShow(MenuPopupHelper.java:175)
at android.support.v7.widget.ActionMenuPresenter$OpenOverflowRunnable.run(ActionMenuPresenter.java:803)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Just in case, in styles.xml I have
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
</style>
<style name="Toolbar" parent="Theme.AppCompat">
</style>
I'm supposed to enchulate more the toolbar, so I added a style for now blank. And in AppTheme, you do not need to change anything, but as it's called in the manifest, leave it.
I would appreciate it because I have many hours in something "supposedly simple".
Greetings