I'm testing the new support library leanback to design apps for TV, and i have a error ever android try to inflate the BrowseFragment and it throws this exception and don't know how to solve it. Thank you so much for your help.
Error -
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.directsportsnetwork.tv/com.directsportsnetwork.tv.ui.TeamSclActivity}: android.view.InflateException: Binary XML file line #67 in com.directsportsnetwork.tv:layout/activity_teamscl: Binary XML file line #24 in com.directsportsnetwork.tv:layout/lb_browse_fragment: Binary XML file line #24 in com.directsportsnetwork.tv:layout/lb_browse_fragment: Error inflating class androidx.leanback.widget.BrowseFrameLayout
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
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)
Caused by: android.view.InflateException: Binary XML file line #67 in com.directsportsnetwork.tv:layout/activity_teamscl: Binary XML file line #24 in com.directsportsnetwork.tv:layout/lb_browse_fragment: Binary XML file line #24 in com.directsportsnetwork.tv:layout/lb_browse_fragment: Error inflating class androidx.leanback.widget.BrowseFrameLayout
Caused by: android.view.InflateException: Binary XML file line #24 in com.directsportsnetwork.tv:layout/lb_browse_fragment: Binary XML file line #24 in com.directsportsnetwork.tv:layout/lb_browse_fragment: Error inflating class androidx.leanback.widget.BrowseFrameLayout
Caused by: android.view.InflateException: Binary XML file line #24 in com.directsportsnetwork.tv:layout/lb_browse_fragment: Error inflating class androidx.leanback.widget.BrowseFrameLayout
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.reflect.Field.get(java.lang.Object)' on a null object reference
at uk.co.chrisjenx.calligraphy.ReflectionUtils.getValue(ReflectionUtils.java:29)
at uk.co.chrisjenx.calligraphy.CalligraphyLayoutInflater.createCustomViewInternal(CalligraphyLayoutInflater.java:203)
at uk.co.chrisjenx.calligraphy.CalligraphyLayoutInflater.access$000(CalligraphyLayoutInflater.java:20)
at uk.co.chrisjenx.calligraphy.CalligraphyLayoutInflater$PrivateWrapperFactory2.onCreateView(CalligraphyLayoutInflater.java:302)
at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:237)
at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1067)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:995)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:959)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1121)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082)
at android.view.LayoutInflater.inflate(LayoutInflater.java:680)
at uk.co.chrisjenx.calligraphy.CalligraphyLayoutInflater.inflate(CalligraphyLayoutInflater.java:60)
at android.view.LayoutInflater.inflate(LayoutInflater.java:532)
at androidx.leanback.app.BrowseFragment.onCreateView(BrowseFragment.java:1318)
at android.app.Fragment.performCreateView(Fragment.java:2505)
at android.app.FragmentManagerImpl.ensureInflatedFragmentView(FragmentManager.java:1491)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1274)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1486)
at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1728)
E/AndroidRuntime: at android.app.FragmentManagerImpl.onCreateView(FragmentManager.java:3562)
at android.app.FragmentController.onCreateView(FragmentController.java:104)
at android.app.Activity.onCreateView(Activity.java:7112)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:229)
at uk.co.chrisjenx.calligraphy.CalligraphyLayoutInflater$PrivateWrapperFactory2.onCreateView(CalligraphyLayoutInflater.java:303)
at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:237)
at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1067)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:995)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:959)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1121)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082)
at android.view.LayoutInflater.inflate(LayoutInflater.java:680)
at uk.co.chrisjenx.calligraphy.CalligraphyLayoutInflater.inflate(CalligraphyLayoutInflater.java:60)
at android.view.LayoutInflater.inflate(LayoutInflater.java:532)
at android.view.LayoutInflater.inflate(LayoutInflater.java:479)
at android.transition.Scene.enter(Scene.java:182)
at com.android.internal.policy.PhoneWindow.transitionTo(PhoneWindow.java:522)
at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:453)
at android.app.Activity.setContentView(Activity.java:3468)
at androidx.activity.ComponentActivity.setContentView(ComponentActivity.java:448)
at com.directsportsnetwork.tv.ui.TeamSclActivity.onCreate(TeamSclActivity.java:55)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
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)
My Activity code is -
package com.directsportsnetwork.tv.ui;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import com.directsportsnetwork.tv.R;
import com.directsportsnetwork.tv.api.DeviceLogManager;
import com.directsportsnetwork.tv.api.Utils;
import org.json.JSONArray;
import java.util.HashMap;
import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper;
public class TeamSclActivity extends FragmentActivity {
private String TAG = TeamSclActivity.class.getSimpleName();
private ImageView topShelfImg, topShelfMask;
private TeamSclFragment mTeamSclFragment;
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
@SuppressWarnings("unchecked")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_teamscl);
IntentFilter filter = new IntentFilter();
filter.addAction("com.directsportsnetwork.tv.STOP");
registerReceiver(broadcastReceiver, filter);
DeviceLogManager.instance().sendTeamSelectionPageData(TeamSclActivity.this);
topShelfImg = (ImageView) findViewById(R.id.top_shelf_image);
topShelfMask = (ImageView) findViewById(R.id.top_shelf_mask);
Intent intent = getIntent();
if (intent != null) {
try {
String channelData = intent.getStringExtra(Utils.EXTRA_CHANNEL_RESPONSE);
HashMap<String, Integer> teamTrnMap = (HashMap<String, Integer>) intent.getSerializableExtra(Utils.EXTRA_TEAM_TRN_MAP);
mTeamSclFragment = (TeamSclFragment) getFragmentManager().findFragmentById(R.id.main_browse_fragment);
mTeamSclFragment.onResponseData(new JSONArray(channelData), teamTrnMap);
} catch (Exception e) {
e.printStackTrace();
}
setTopShelfMask();
final Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
try {
mHandler.postDelayed(this, 300);
if (mTeamSclFragment.getView() != null && getCurrentFocus() instanceof RelativeLayout) {
mTeamSclFragment.getView().requestFocus();
mHandler.removeCallbacks(this);
mHandler.removeCallbacksAndMessages(null);
}
}catch (Exception e) {
e.printStackTrace();
}
}
}, 300); //Changes START HERE FOR NEW CHANGES - 10/20/2018
}
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
@SuppressLint("MissingSuperCall")
@Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super(). Bug on API Level > 11.
}
// remot Button OnClickListener methods
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
// Remove shadow over topShelfImage at here
if (mTeamSclFragment != null) {
mTeamSclFragment.startBackgroundTimer();
}
default:
return super.onKeyUp(keyCode, event);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
|| keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP) {
// Add shadow over topShelfImage at here
topShelfImg.setAlpha(0.3f);
}
if (mTeamSclFragment != null) {
mTeamSclFragment.onMyKeyDown(keyCode, event);
}
return false;
}
public ImageView getTopShelfImg() {
return topShelfImg;
}
public void setTopShelfMask() {
if (Utils.SHOW_TOP_SHELF_MASK) {
topShelfMask.setBackground(ContextCompat.getDrawable(TeamSclActivity.this, R.drawable.ic_mask_bottom));
}
}
}
My Fragment code -
package com.directsportsnetwork.tv.ui;
import static androidx.leanback.app.BackgroundManager.getInstance;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.leanback.app.BackgroundManager;
import androidx.leanback.app.BrowseFragment;
import androidx.leanback.widget.ArrayObjectAdapter;
import androidx.leanback.widget.FocusHighlight;
import androidx.leanback.widget.HeaderItem;
import androidx.leanback.widget.ListRow;
import androidx.leanback.widget.ListRowPresenter;
import androidx.leanback.widget.OnItemViewClickedListener;
import androidx.leanback.widget.OnItemViewSelectedListener;
import androidx.leanback.widget.Presenter;
import androidx.leanback.widget.Row;
import androidx.leanback.widget.RowPresenter;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.directsportsnetwork.tv.R;
import com.directsportsnetwork.tv.api.OnResponseReceived;
import com.directsportsnetwork.tv.api.TvApplication;
import com.directsportsnetwork.tv.api.Utils;
import com.directsportsnetwork.tv.model.Team;
import com.directsportsnetwork.tv.presenter.TeamPresenter;
import com.directsportsnetwork.tv.provider.DataBaseHelper;
import org.json.JSONArray;
import org.json.JSONObject;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class TeamSclFragment extends BrowseFragment implements OnResponseReceived {
private final String TAGS = "TeamSclFragment";
private final Handler mHandler = new Handler();
private Drawable mDefaultBackground;
private DisplayMetrics mMetrics;
private Timer mBackgroundTimer;
private URI mBackgroundURI;
private URI defaultBackgroundURI;
public Team selectedTeam;
private JSONArray teamData;
private HashMap<String, Integer> teamTrnMap;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
private boolean isFavoriteDisable(String teamId) {
return !(teamTrnMap != null && teamTrnMap.get(teamId) != null);
}
private int getTrnByTeamId(String teamId) {
return teamTrnMap.get(teamId);
}
@Override
public void onResponseData(JSONArray data, HashMap<String, Integer> teamTrnMap) {
try {
Log.e(TAGS, "apiResponse: " + data);
teamData = data;
this.teamTrnMap = teamTrnMap;
prepareBackgroundManager();
setupUIElements();
// Set rows as per data fetched form API
loadTeamRows(teamData);
setupEventListeners();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (null != mBackgroundTimer) {
mBackgroundTimer.cancel();
}
}
@Override
public void onResume() {
super.onResume();
if (TvApplication.isFavChanged && teamData != null) {
loadTeamRows(teamData);
TvApplication.isFavChanged = false;
if (getView() != null) {
getView().requestFocus();
setSelectedPosition(0, true);
startBackgroundTimer();
}
}
}
@Override
public void onPause() {
super.onPause();
}
public void onMyKeyDown(int keyCode, KeyEvent event) {
//do whatever you want here
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
getActivity().finish();
getActivity().overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
break;
}
}
private void loadTeamRows(JSONArray teamCategoryList) {
try {
ArrayList<Team> favTeamList = new ArrayList<>();
if (Utils.isStoragePermissionGranted(getActivity())) {
DataBaseHelper dataBase = DataBaseHelper.getInstance(getActivity());
favTeamList = dataBase.getAllFavorites();
} else {
favTeamList.add(null);
Utils.showToast(getActivity(), getResources().getString(R.string.no_storage_permission));
}
ListRowPresenter mListRowPresenter = new ListRowPresenter(FocusHighlight.ZOOM_FACTOR_NONE, true);
ArrayObjectAdapter mRowsAdapter = new ArrayObjectAdapter(mListRowPresenter);
TeamPresenter teamPresenter = new TeamPresenter();
for (int i = 0; i < teamCategoryList.length() + 1; i++) {
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(teamPresenter);
if (i == 0) {
// This is to create Favorite card row
for (int index = 0; index < favTeamList.size(); index++) {
if (favTeamList.get(index) == null) {
listRowAdapter.add(getResources().getString(R.string.favorites));
} else {
Team team = favTeamList.get(index);
team.setIsFavorite(1);
if (isFavoriteDisable(team.getId())) {
// TODO: Team is disabled, remove it from favorites
DataBaseHelper dataBase = DataBaseHelper.getInstance(getActivity());
dataBase.removeFavorite(team.getId());
TvApplication.isFavChanged = true;
continue;
} else {
team.setReleaseNo(getTrnByTeamId(team.getId()));
}
listRowAdapter.add(team);
}
}
HeaderItem header = new HeaderItem(i, "Favorites");
mRowsAdapter.add(new ListRow(header, listRowAdapter));
} else {
JSONArray teamList = teamCategoryList.getJSONObject(i - 1).getJSONArray("team");
String category = teamCategoryList.getJSONObject(i - 1).getString("name");
String categoryId = teamCategoryList.getJSONObject(i - 1).getString("id");
for (int index = 0; index < teamList.length(); index++) {
JSONObject teamObj = teamList.getJSONObject(index);
String id = teamObj.getString("id");
String name = teamObj.getString("name");
String shortdesc = teamObj.getString("shortdesc");
String longdesc = teamObj.getString("longdesc");
int trn = teamObj.getInt("trn");
//trn stands for Team Release Number
Team team = new Team();
team.setCatId(categoryId);
team.setCatName(category);
team.setId(id);
team.setName(name);
team.setShortdesc(shortdesc);
team.setLongdesc(longdesc);
team.setIsFavorite(0);
team.setReleaseNo(trn);
if (category.equalsIgnoreCase("NASCAR")) {
team.setIsNascar(1);
} else {
team.setIsNascar(0);
}
listRowAdapter.add(team);
}
HeaderItem header = new HeaderItem(i, category);
mRowsAdapter.add(new ListRow(header, listRowAdapter));
}
}
setAdapter(mRowsAdapter);
} catch (Exception e) {
e.printStackTrace();
}
}
private void prepareBackgroundManager() {
BackgroundManager mBackgroundManager = getInstance(getActivity());
mBackgroundManager.attach(getActivity().getWindow());
mDefaultBackground = ContextCompat.getDrawable(getActivity(), R.drawable.default_background);
mBackgroundManager.setColor(Color.BLACK);
mMetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
}
private void setupUIElements() {
getTitleView().setVisibility(View.GONE);
// To hide left side header for BrowseFragment
setHeadersState(HEADERS_DISABLED);
setHeadersTransitionOnBackEnabled(true);
}
private void setupEventListeners() {
setOnItemViewClickedListener(new ItemViewClickedListener());
setOnItemViewSelectedListener(new ItemViewSelectedListener());
}
protected void updateBackground(String uri) {
try {
int width = mMetrics.widthPixels;
int height = mMetrics.heightPixels;
final TeamSclActivity activity = ((TeamSclActivity) getActivity());
if (activity.getTopShelfImg().getDrawable().getConstantState() == getResources().getDrawable(R.drawable.ic_start).getConstantState() && (uri == defaultBackgroundURI.toString())) {
} else {
//start
if (activity != null) {
Glide.with(activity).load(uri).error(mDefaultBackground).placeholder(R.drawable.teamblank).into(new CustomTarget<Drawable>(width, height) {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
activity.getTopShelfImg().setImageDrawable(resource);
Utils.crossfade(activity.getTopShelfImg());
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
});
}
//end
}
mBackgroundTimer.cancel();
} catch (Exception e) {
e.printStackTrace();
}
}
public void startBackgroundTimer() {
if (mBackgroundTimer != null) {
mBackgroundTimer.cancel();
}
mBackgroundTimer = new Timer();
mBackgroundTimer.schedule(new UpdateBackgroundTask(), Utils.BACKGROUND_UPDATE_DELAY);
}
private final class ItemViewClickedListener implements OnItemViewClickedListener {
@Override
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) {
if (item instanceof Team) {
Team team = (Team) item;
Intent intent = new Intent(getActivity(), TeamChnlActivity.class);
intent.putExtra(Utils.EXTRA_TEAM, team);
startActivity(intent);
} else if (item instanceof String) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(getResources().getString(R.string.favorite_alert_msg));
builder.setCancelable(true);
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
}
private final class ItemViewSelectedListener implements OnItemViewSelectedListener {
@Override
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) {
if (item instanceof Team) {
Team team = ((Team) item);
try {
selectedTeam = team;
mBackgroundURI = new URI(team.getTopShelfImageUrl(team.getId(), team.getReleaseNo()));
defaultBackgroundURI = new URI(Utils.MEDIA_PREFIX_URL + "/tv/images/app/start.jpg?");
if (team.getIsFavorite() == 1) {
startBackgroundTimer();
}
} catch (Exception e) {
e.printStackTrace();
}
} else if (item instanceof String) {
try {
selectedTeam = null;
Random random = new Random();
mBackgroundURI = new URI(Utils.MEDIA_PREFIX_URL + "/tv/images/app/start.jpg?" + random.nextInt(100));
defaultBackgroundURI = mBackgroundURI;
startBackgroundTimer();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private class UpdateBackgroundTask extends TimerTask {
@Override
public void run() {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mBackgroundURI != null) {
updateBackground(mBackgroundURI.toString());
}
}
});
}
}
}
My activity_teamscl.xml code -
<?xml version="1.0" encoding="utf-8"?>
<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">
<fragment
android:id="@+id/main_browse_fragment"
android:name="com.directsportsnetwork.tv.ui.TeamSclFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignTop="@+id/center_baseline"
tools:context=".ui.TeamSclActivity"
tools:deviceIds="tv"
tools:ignore="MergeRootFrame" />
</RelativeLayout>