I am using a BottomNavigationDrawer/BottomSheetDialog from the following example, where the BottomNavigationDrawer switches between multiple fragments inside a single activity.
While implementing the BottomNavigationDrawer, I realized that when the fragments were swapped without using the menu, i.e. by clicking a button in a fragment, this left the menu selection in an inconsistent state. Also, the solution of using a function in the main activity to trigger the FragmentTransaction caused crashes.
public void resetNavDefault(){
if(fragment == null) {
fragment = new BottomNavigationDrawerFragment();
navigationView = fragment.getNavigationView();
} else navigationView = fragment.getNavigationView();
//navigationView.getMenu().getItem(0).setChecked(true);
Log.d(TAG, "resetNavDefault: setting check");
MenuItem item = navigationView.getMenu().getItem(0);
navigationView.getMenu().performIdentifierAction(item.getItemId(), 0);
}
I realised that this was caused by getSupportFragmentManager being null and/or the fragment not being attached, and using getChildFragmentManager was not the right solution, as I do not use nested fragments, only multiple fragments in a single activity.
I also tried implementing this workaround where the onDetach is overridden to make the childFragmentManager accessible.
This fix prevents the app from crashing with an NPE (due to the if (!isAdded()) return; condition) but leaves the button that launches the new fragment unresponsive (the button does not work) .
How do I navigate between two fragments using FragmentTransaction without causing an NPE, and without leaving the menu selection in an inconsistent state?
My BottomNavigationDrawer implementation is as follows:
BottomNavigationDrawer
public class BottomNavigationDrawerFragment extends BottomSheetDialogFragment {
BottomNavigationDrawerFragment fragment;
public NavigationView navigationView;
ImageView close, menu;
Statuser statuser;
RevivDatabase database;
String email, fname, lname;
TextView txtUsername, txtEmail;
private static String TAG = "BottomNavDrawerFragment";
public BottomNavigationDrawerFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_bottomsheet, container, false);
txtUsername = view.findViewById(R.id.txtUsername);
txtEmail = view.findViewById(R.id.txtEmail);
navigationView = view.findViewById(R.id.navigation_view);
database = RevivDatabase.getDatabase(getActivity());
statuser = database.revivDao().getUserDetails();
fname = statuser.getFname();
lname = statuser.getLname();
email = statuser.getEmail();
txtEmail.setText(email);
txtUsername.setText(fname+" "+lname);
setRetainInstance(true);
close = view.findViewById(R.id.imgClose);
fragment = this;
close.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
fragment.dismiss();
}
});
navigationView.setItemIconTintList(null);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
menuItem.setChecked(true);
int id = menuItem.getItemId();
FragmentManager manager;
try {
manager = getActivity().getSupportFragmentManager();
} catch (NullPointerException e) {
if (!isAdded()) return false;
manager = getChildFragmentManager();
Log.e(TAG, "onNavigationItemSelected: ", e);
}
switch (id){
case R.id.app_bar_incident:
navigationView.getMenu().findItem(id).setChecked(true);
manager.beginTransaction().replace(R.id.containerFrameLayout, new FragmentRevivIncidentDashboard()).commit();
Toast.makeText(getContext(), "Request Incident", Toast.LENGTH_SHORT).show();
fragment.dismiss();
break;
case R.id.app_bar_housecall:
navigationView.getMenu().findItem(id).setChecked(true);
manager.beginTransaction().replace(R.id.containerFrameLayout, new FragmentRevivHousecallDashboard()).commit();
fragment.dismiss();
Toast.makeText(getContext(), "Request Housecall", Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
navigationView.getMenu().findItem(id).setChecked(true);
manager.beginTransaction().replace(R.id.containerFrameLayout, new FragmentRevivSettingsMain()).commit();
Toast.makeText(getActivity().getApplicationContext(), "Settings", Toast.LENGTH_SHORT).show();
fragment.dismiss();
break;
}
return true;
}
});
return view;
}
#Override
public void onDetach() {
super.onDetach();
try {
Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public NavigationView getNavigationView() {
return navigationView;
}
}
My Error Message
09-13 00:26:32.996 28025-28025/com.package.name E/AndroidRuntime:
FATAL EXCEPTION: main
Process: com.package.name, PID: 28025
java.lang.IllegalStateException: Fragment has not been attached yet.
at android.support.v4.app.Fragment.instantiateChildFragmentManager(Fragment.java:2386)
at android.support.v4.app.Fragment.getChildFragmentManager(Fragment.java:842)
at com.package.name.Fragments.BottomNavigationDrawerFragment$2.onNavigationItemSelected(BottomNavigationDrawerFragment.java:108)
at android.support.design.widget.NavigationView$1.onMenuItemSelected(NavigationView.java:170)
at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:840)
at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:991)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:981)
at android.support.v7.view.menu.MenuBuilder.performIdentifierAction(MenuBuilder.java:977)
at com.package.name.Reviv.resetNavDefault(Reviv.java:644)
at com.package.name.Fragments.FragmentRevivSettingsMain$1.onClick(FragmentRevivSettingsMain.java:77)
at android.view.View.performClick(View.java:6303)
at android.view.View$PerformClick.run(View.java:24828)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6798)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
First implement the button click event in your MainActivity as in this page. Then assuming you have your BottomNavigationDrawerFragment instance in MainActivity, just get the view through this instance and make the setSelection call for navigation menu through this view as the button is clicked. Make sure that you are getting the view through instance after bottomNavDrawerFragment.show(..) call is made. Otherwise you will get a NPE error.
Related
I have a problem with android studio. I use a fragment with a bottomNavigationView. It works fine if you click on the bottomNavigation. But if you simulate a click on the bottomNavigation it works for the first time and at the second time if you simulate the performclick again, it does not work.
I used also view.callOnClick(); and for the fragment add and remove fragment, but both do not function for my problem. I really appreciate it, if anyone can solve my problem.
Here is the Code:
`
public class ProfileFragment extends Fragment {
private Button send_order_button;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstaceState) {
return inflater.inflate(R.layout.profile_fragment, container,false);
}
#Override
public void onStart() {
send_order_button = (Button) getView().findViewById(R.id.auftrag_abschicken);
}
send_order_button.setOnClickListener(new View.OnClickListener() {
ProfilActivity pa = new ProfilActivity();
pa.changeFragment();
getActivity().finishActivity(ProfilActivity.class.hashCode());
}
}`
`
public class ProfilActivity extends AppCompatActivity {
public ProfilActivity() {}
public static Fragment selectedFragment = null;
public static BottomNavigationView bottomNavigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profil);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(navListener);
View view = bottomNavigationView.findViewById(R.id.nav_chat);
view.performClick();
}
public void changeFragment() {
// bottomNavigationView.setSelectedItemId(R.id.nav_store);
View view = bottomNavigationView.findViewById(R.id.nav_store);
view.performClick();
}
public BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.nav_user :
selectedFragment = new ProfileFragment();
break;
case R.id.nav_chat :
selectedFragment = new MailFragment();
break;
case R.id.nav_store:
selectedFragment = new ShopFragment();
break;
}
try {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
selectedFragment, "fragment").commitAllowingStateLoss();
} catch (Exception e) {
e.printStackTrace();
};
return true;
}
};
}`
It looks like you're trying to set the default selected item in the BottomNavigationView. Why not just use bottomNavigationView.setSelectedItemId(R.id.nav_store); ?
I am using Bottom Navigation Layout to show 5 fragments but the problem is after every onResume is called each fragment start lagging more and more.
This is my main activity with contain bottom navigation
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.menu_home:
if (!selectedFragment.equalsIgnoreCase(Consts.MasterHomeFragment)) {
openMasterHomeFragment();
}
break;
case R.id.menu_wallet:
if (!isSessionActive()) {
showLoginBottomDialog();
return false;
} else {
if (!selectedFragment.equalsIgnoreCase(Consts.WalletFragment))
openWalletFragment();
}
break;
case R.id.menu_portfolio:
if (!isSessionActive()) {
showLoginBottomDialog();
return false;
} else {
if (!selectedFragment.equalsIgnoreCase(Consts.PortfolioFragment))
openPortfolioFragment();
}
break;
on each method i do
public void openPortfolioFragment() {
eventTracker.track(EventTracker.HOME_PORTFOLIO_NAV_CLICKED);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
PortfolioFragment portfolioFragment = new PortfolioFragment();
transaction.replace(R.id.activity_home_main_frame, portfolioFragment);
transaction.commit();
selectedFragment = Consts.PortfolioFragment;
}
public void openProfileFragment() {
eventTracker.track(EventTracker.HOME_ACCOUNT_NAV_CLICKED);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
ProfileFragment profileFragment = new ProfileFragment();
transaction.replace(R.id.activity_home_main_frame, profileFragment);
transaction.commit();
selectedFragment = Consts.ProfileFragment;
}
and oneach fragment onresume calling api
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_wallet, container, false);
unbinder = ButterKnife.bind(this, view);
initViewPager(view);
return view;
}
#Override
public void onResume() {
super.onResume();
loadDataFromApi();
}
and rendering data
#Override
public void onDataLoaded(MasterHomeResponse response) {
if (getActivity() != null && isAdded()) {
masterHomeResponse = response;
hideRefreshing();
initPortfolio(response);
initInbox(response.getInbox());
initAssets(response);
initTutorial(response);
initFeeds(response);
showBottomMoreFloatingButton();
boolean dismissIntro = sharedPreferenceHelper.getSamplePreference().getShowCase();
showGuideView(response, dismissIntro);
}
}
when ever i go to background and come back to application every fragment start lagging on scrolling
I was searching solution for this issue i have got this link Android Facebook SDK lowers app performance me also using facebook sdk for login purpose so making autologging value to false my issue resolved.
I will try to explain at best, adding references and images in which
I think it is difficult to explain in words the error I encountered.
Working with the fragments and the Navigation Drawer I've faced this
bug:
From time to time, when I open the navigation menu, the previous
fragment is duplicated or loaded again. This thing is completely
random, without a precise scheme. The only thing that seems
connected is the RecyclerView and the Navigation Drawer.
Just because I do not know where I'm wrong, write in the comments if you
need something, code or other information and from time to time I'll add it
to the original question.
I am not receiving any errors and to help both me and you add some code and
images of how that fragment is loaded without bugs:
#Override
public boolean onNavigationItemSelected(MenuItem item) {
Fragment fragment = null;
Class aclass = null;
Bundle args = new Bundle();
Intent intentOperatore = getIntent();
String mParamOperatore = intentOperatore.getStringExtra(ARG_PARAM_OPERATORE);
boolean navigation = Boolean.FALSE;
boolean intent = Boolean.FALSE;
boolean scan = Boolean.FALSE;
boolean exit = Boolean.FALSE;
try{
switch (item.getItemId()){
case R.id.nav_home:
aclass = HomeFragment.class;
fragment = (Fragment) aclass.newInstance();
args.putString(ARG_PARAM_OPERATORE,mParamOperatore);
fragment.setArguments(args);
navigation = Boolean.TRUE;
break;
case R.id.nav_procedura_immobiliare:
aclass = FiltroFragment.class;
fragment = (Fragment) aclass.newInstance();
args.putString(ARG_CHECK_CLASS,"immobiliari");
fragment.setArguments(args);
navigation = Boolean.TRUE;
break;
case R.id.nav_procedura_mobiliare:
aclass = FiltroFragment.class;
fragment = (Fragment) aclass.newInstance();
args.putString(ARG_CHECK_CLASS,"mobiliari");
fragment.setArguments(args);
navigation = Boolean.TRUE;
break;
case R.id.nav_localizza_procedura:
aclass = LocalizzaActivity.class;
intent = Boolean.TRUE;
break;
case R.id.nav_ricognizione:
aclass = RicognizioneFragment.class;
fragment = (Fragment) aclass.newInstance();
args.putString(ARG_PARAM_RICOGNIZIONE,""); //TODO: Add param here.
fragment.setArguments(args);
navigation = Boolean.TRUE;
break;
case R.id.nav_qrcode:
scan = Boolean.TRUE;
break;
case R.id.nav_exit:
exit = Boolean.TRUE;
break;
}
if(navigation) { // Navigazione per i fragment
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
} if(intent) { // Navigazione per le activity
Intent myIntent = new Intent(getApplicationContext(),aclass);
myIntent.putExtra(ARG_PARAM_OPERATORE,mParamOperatore);
startActivity(myIntent);
finish();
} if(scan) {
new MVBarcodeScanner.Builder()
.setScanningMode(MVBarcodeScanner.ScanningMode.SINGLE_AUTO)
.setFormats(Barcode.QR_CODE)
.build()
.launchScanner(MainActivity.this,REQ_CODE);
} if(exit) { // Navigazione per l'uscita
MaterialDialog dialog = new MaterialDialog.Builder(this)
.title(R.string.title_exit)
.content(R.string.summary_exit)
.positiveText(R.string.action_exit)
.onPositive(new MaterialDialog.SingleButtonCallback() {
#Override
public void onClick(MaterialDialog dialog, DialogAction which) {
finish();
}
})
.negativeText(R.string.action_no)
.show();
}
} catch (Exception e) {
Log.e(this.getClass().getName(), e.getMessage(), e);
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
Edit:
I also notice another thing that recycling is not the only thing to
duplicate. There is also the toolbar item that is duplicated:
Edit 2:
- I've added the onCreateOptionsMenu and some code that i run in the
onCreateView:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
//inflater.inflate(R.menu.procedura_menu_action, menu);
inflater.inflate(R.menu.procedura_menu_list, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_procedure_list, container, false);
Context context = view.getContext();
setHasOptionsMenu(true);
recyclerView = (RecyclerView) view.findViewById(R.id.rvProcedure);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(context);
mAdapter = new ProcedureAdapter(context,procedure,this);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new DividerItemDecoration(context,LinearLayoutManager.VERTICAL));
recyclerView.setAdapter(mAdapter);
actionModeCallback = new ActionModeCallback();
Toolbar toolbar = view.findViewById(R.id.toolbar);
toolbar.setTitle(getString(R.string.title_lista_procedure) + " " + mCheckClass);
toolbar.setNavigationIcon(R.drawable.ic_menu_navigator);
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
DrawerLayout drawerLayout = (DrawerLayout) getActivity().findViewById(R.id.drawer_layout);
if(drawerLayout.isDrawerOpen(GravityCompat.START)){
drawerLayout.closeDrawer(GravityCompat.START);
} else {
drawerLayout.openDrawer(GravityCompat.START);
}
}
});
floatingActionButton = (FloatingActionButton) view.findViewById(R.id.fab_new);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
args.putString(ARG_PARAM_TIPOLOGIA,mParamTipologia); //Passa la procedura selezionata se siamo in modifica
args.putString(ARG_PARAM_PROCEDURA,new Gson().toJson(procedure.get(lastPosition)));
if(actionMode != null) //Leva la selezione se รจ presente, prima di passare ad un'altro fragment.
enableActionMode(lastPosition);
try {
if ((getActivity()) != null) {
FragmentManager fragmentManager = ((AppCompatActivity)getActivity()).getSupportFragmentManager();
Class fragmentClass = ProceduraFragment.class;
Fragment fragment = (Fragment) fragmentClass.newInstance();
fragment.setArguments(args);
fragmentManager.beginTransaction().replace(R.id.flContent, fragment).addToBackStack(null).commit();
}
} catch (java.lang.InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
});
//TODO: Implements here the load logic for procedure.
if(mParamProcedura != null && !(procedure.size() > 0)) {
procedure.add(mParamProcedura);
} else if(!(procedure.size() > 0)) {
refreshList(AlphaMAS.getData());
}
return view;
}
Why create a new fragment instance everytime? Try something like this:
if (fragment == null)
fragment = (Fragment) aclass.newInstance();
Inside your layout in both Fragments use this :
android:clickable="true"
android:focusable="true"
Solution
Set background to both of your xml file's parent layout.
android:background="#color/background_color_which_you_want"
Edit 1:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.procedura_menu_list, menu);
return super.onCreateOptionsMenu(menu);
}
public class MainLibraryFragment extends Fragment implements PlaylistChangedInterface {
AudioItemSelectedListener mCallback;
// Container Activity must implement this interface
public interface AudioItemSelectedListener {
// public void onAudioItemSelected(int position);
public void onAudioItemSelected(Audio audioSelected);
}
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private Context context;
private ArrayList<Audio> listToDisplay;
private String TAG = "MainLibraryFragment";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
context = getActivity();
MemoryManagement memoryManagement = new MemoryManagement(context);
listToDisplay = memoryManagement.loadAudioList(MemoryManagement.MAIN_LIST_KEY);
try {
//Expression is meaningless but tests if null.
//TODO, should catch this in loadAudioList.
if (listToDisplay.isEmpty()){}
} catch (NullPointerException e){
defaultList();
}
View rootView = inflater.inflate(R.layout.fragment_top_rated, container, false);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(getContext());
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.addItemDecoration(new DividerItemDecoration(getContext(), LinearLayoutCompat.VERTICAL));
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.addOnItemTouchListener(new CustomTouchListener(context, new onItemClickListener() {
#Override
public void onClick(View view, int index) {
mCallback.onAudioItemSelected(listToDisplay.get(index));
}
}));
mAdapter = new SongListAdapter2(listToDisplay, context);
mRecyclerView.setAdapter(mAdapter);
return rootView;
}
private void defaultList(){
listToDisplay = new ArrayList<>();
listToDisplay.add(new Audio("You need to add some songs!"));
}
#Override
public void playListChanged(ArrayList<Audio> arrayList) {
Log.d(TAG, "updateTop: in.");
if (!arrayList.isEmpty()) {
listToDisplay = arrayList;
}else {
defaultList();
}
updateListView();
Log.d(TAG, "updateTop: out.");
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
context = getContext();
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (AudioItemSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement AudioItemSelectedListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mCallback = null;
}
private void updateListView(){
Log.d(TAG, "updateTop: in.");
((SongListAdapter2) mAdapter).refreshList(listToDisplay);
Log.d(TAG, "updateTop: out.");
}
}
I have added refreshList():
public void refreshList(ArrayList<Audio> list) {
this.list = list;
notifyDataSetChanged();
}
And then the error message:
--------- beginning of crash
06-09 15:14:24.275 9114-9114/com.bteq.audia E/AndroidRuntime: FATAL
EXCEPTION: main
Process: com.bteq.audia, PID: 9114
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.bteq.audia.SongListAdapter2.refreshList(java.util.ArrayList)' on a null object reference
at com.bteq.audia.MainLibraryFragment.updateListView(MainLibraryFragment.java:128)
at com.bteq.audia.MainLibraryFragment.playListChanged(MainLibraryFragment.java:100)
at com.bteq.audia.MainActivity.onDialogPositiveClick(MainActivity.java:195)
at com.bteq.audia.AddSongDialog$2.onClick(AddSongDialog.java:47)
at android.support.v7.app.AlertController$ButtonHandler.handleMessage(AlertController.java:166)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6753)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:482)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
06-09 15:14:24.281 9114-9114/com.bteq.audia W/OPDiagnose:
getService:OPDiagnoseService NULL
The MainActivity that contains the Pager. I tried to remove as much code as I could that wasn't relevant.
public class MainActivity extends AppCompatActivity implements MainLibraryFragment.AudioItemSelectedListener, AddSongDialog.NoticeDialogListener, ShowQueueDialog.ShouldClearAll {
private MemoryManagement memoryManagement;
private ViewPager viewPager;
private com.bteq.audia.PagerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
memoryManagement = new MemoryManagement(this);
setContentView(R.layout.activity_main);
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
initialiseViews();
}
public void initialiseViews() {
//Fills the titles of all the tabs.
String[] tabTitles = getTabTitles();
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabLayout);
for (int i = 0; i < tabTitles.length; i++) {
tabLayout.addTab(tabLayout.newTab().setText(tabTitles[i]));
}
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
//Sets up the ViewPager and creates the functionality to make them changeable.
viewPager = (ViewPager) findViewById(R.id.pager);
adapter = new PagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
setupBottomView();
}
//method used as main control to the service from this activity.
private void audioActionDo(String audioAction) {
Intent intent = new Intent("audio_control_intent");
intent.putExtra("button_pressed", audioAction);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
/*
Method tells the activity which item in the shown playlist has been selected. This should then cause that item to play if possible.
//TODO, fill in body of method.
*/
#Override
public void onAudioItemSelected(Audio audio) {
songSelected(audio);
Log.d("MainActivity", "onAudioItemSelected: At end");
}
#Override
public void onDialogPositiveClick(String titleString, String artistString, String albumString, String genreString) {
Audio audioToAdd = new Audio(genreString, titleString, albumString, artistString);
memoryManagement.addAudioToList(audioToAdd, MemoryManagement.MAIN_LIST_KEY);
Fragment fragment = adapter.getItem(0);
PlaylistChangedInterface playlistChangedInterface = (PlaylistChangedInterface) fragment;
playlistChangedInterface.playListChanged(memoryManagement.loadAudioList(MemoryManagement.MAIN_LIST_KEY));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_top, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
//TODO, take the user to the app settings page.
// User chose the "Settings" item, show the app settings UI...
return true;
case R.id.action_favorite:
//TODO, make this favourite the current Audio.
// User chose the "Favorite" action, mark the current item
// as a favorite...
memoryManagement.clearPrefsValue(MemoryManagement.MAIN_LIST_KEY);
return true;
case R.id.action_add_new_song:
showAddSongDialog();
return true;
case R.id.action_show_queue:
showQueueDialog();
return true;
case R.id.action_add_from_internal:
return true;
default:
// If we got here, the user's action was not recognized.
// Invoke the superclass to handle it.
return super.onOptionsItemSelected(item);
}
}
public void showAddSongDialog() {
DialogFragment newFragment = new AddSongDialog();
newFragment.show(getSupportFragmentManager(), "missiles");
}
public void showQueueDialog() {
DialogFragment newFragment = new ShowQueueDialog();
newFragment.show(getSupportFragmentManager(), "showQueue");
}
//Should immediately play a song then be able to continue with the queued audio.
public void songSelected(Audio audioToAdd) {
}
//clears the entire queue but completes playback of current audio.
private void clearCurrentQueue() {
memoryManagement.clearPrefsValue(MemoryManagement.QUEUE_KEY);
}
// Utility method. Returns the locale titles for the tabs in the viewpager.
private String[] getTabTitles() {
return getResources().getStringArray(R.array.tab_titles);
}
#Override
public void clearAllPressed() {
clearCurrentQueue();
}
private void setupBottomView() {
ImageView playButton = (ImageView) findViewById(R.id.bottom_play);
ImageView replayButton = (ImageView) findViewById(R.id.bottom_replay);
ImageView skipBackButton = (ImageView) findViewById(R.id.bottom_skip_back);
ImageView skipForwardButton = (ImageView) findViewById(R.id.bottom_skip_next);
ImageView shuffleButton = (ImageView) findViewById(R.id.bottom_shuffle);
playButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// playAudio(storageUtility2.loadAudioIndex());
audioActionDo(getResources().getString(R.string.broadcast_action_playpause));
}
});
replayButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
audioActionDo(getResources().getString(R.string.broadcast_action_loop));
}
});
skipBackButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
audioActionDo(getResources().getString(R.string.broadcast_action_skip_back));
}
});
skipForwardButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
audioActionDo(getResources().getString(R.string.broadcast_action_skip_forward));
}
});
shuffleButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
audioActionDo(getResources().getString(R.string.broadcast_action_shuffle));
}
});
}
}
I get a null pointer exception whenever the method updateListView is called. The fragment initially displays with no problem, but when a new entry is added to the ArrayList and the updateListView is called - it stops. The log shows that mAdapter is null. I don't know enough about android yet to understand why mAdapter becomes null after it is used before.
Sorry for large amount of code but I'm completely stumped. Thanks.
In my opinion this is because your variable mAdapter is declared as of type RecyclerView.Adapter which is an interface which does not declare your method, refreshList(). Therefore if you intend to use the type RecyclerView.Adapter, only the methods declared in the interface could be called by using the reference variable. If you intend to call methods implemented by yourself other than whats overridden from the interface, the reference type SongListAdapter2 has to be used.
Simple fix is to change the RecyclerView.Adapter to SongListAdapter2 at the declaration of the mAdapter.
Ps. Check android docs to see the methods declared by the RecyclerView.Adapter.
It depends on how you are accessing the adapter in the RecyclerView. If you look at this line Fragment fragment = adapter.getItem(0), you are trying to access the first fragment in your ViewPager's adapter. getItem usually won't get called again after the ViewPager has layout its fragments which means your call to access the RecyclerView's adapter in the first fragment in the ViewPager will be pointing to a null adapter even though the fragment might exist (and you might even be calling a wrong fragment). Use this Fragment fragment = getChildFragmentManager().getFragments().get(0) to access the right fragment which will ensure the RecyclerView adapter won't be null. Change getChildFragmentManager() to getFragmentManager() if your ViewPager is in an Activity.
I am developing an android app and I want to use a toolbar and a navigation drawer inside a fragment. I created an inner class named Supportclass and then use the method named setUptoolbar in the onCreateView method but I got an abnormal error.
What do you think i should do? Thank you in advance and sorry for my broken English. :)
Fragment code:
public class FragmentVRList extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_main,container,false);
View cardView = inflater.inflate(R.layout.card_vr,container,false);
Generator generator = new Generator();
RecyclerView recyclerView = (RecyclerView)rootView.findViewById(R.id.recycle);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
AdapterVRList adapter = new AdapterVRList(getActivity(), Generator.getData());
recyclerView.setAdapter(adapter);
recyclerView.setNestedScrollingEnabled(false);
SupportClass supportClass = new SupportClass();
supportClass.setUptoolbar(getActivity(),rootView);
final TeacherNet teacher = new TeacherNet(getActivity());
int Length = Generator.getData().size();
final JSONObject object = new JSONObject();
for (int position = 1;position<Length;position++){
switch (position){
case 1:
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
object.put("vrcode","1");
teacher.SelectContent(object);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
case 2:
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
object.put("vrcode","2");
teacher.SelectContent(object);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
case 3:
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
object.put("vrcode","3");
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
}
return rootView;
}
private class SupportClass extends AppCompatActivity{
public void setUptoolbar(Activity activity, View view){
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawerLayout = (DrawerLayout) view.findViewById(R.id.drawer);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(activity,drawerLayout,toolbar,0,0);
toggle.syncState();
drawerLayout.addDrawerListener(toggle);
}
}
}
This is the error:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference
You are all the way wrong with your approach. You can do it without defining a new class which extends activity. You always have reference to underlying activity via getActivity (). Even if you want to keep a reference just use MainActivity a = (MainActivity) getActivity () assuming that your fragment is attached to MainActivity. Then operate on a. You are getting that error because you are using
SupportClass supportClass = new SupportClass();
Activities are started using Context.startActivity(Intent intent). It seems that you don't intend to start new activity. You just want to change properties of underlying activity. So as I said above use
MainActivity a = (MainActivity) getActivity () and play with a like a.setSupportActionBar ().
you are using the wrong hierarchy. Correct way is:
Activity -> contains your toolbar, drawer and fragment holder (e.g.
frame layout or viewpager)
Now if you want to open the drawer from some action in fragment you have to add abstract event listener in fragment which will be implemented by activity.
see this quick link on github for more : http://guides.codepath.com/android/fragment-navigation-drawer