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
Related
As you can see below, I have this Fragment layout from my bottom navigator:
So, when application user click on card item from recycle view, I would like to open another fragment over this Search Fragment. I'm trying to to that, but occurs this error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: mobhair.com.br, PID: 538
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference
at android.support.v7.widget.RecyclerView.findMinMaxChildLayoutPositions(RecyclerView.java:4101)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3835)
I really don't know which the problem. Sou could you please help me?
Follow what I have done so far:
Search Fragment:
public class SearchFragment extends Fragment {
private SearchViewAdataper searchViewAdataper;
private RecyclerView recyclerView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.search_screen_fragment, container, false);
final ProgressDialog progressDialog = new ProgressDialog(view.getContext());
Toolbar mToolbar = (Toolbar) view.findViewById(R.id.toolbar);
mToolbar.setTitleTextColor(Color.WHITE);
mToolbar.setTitle(R.string.title_search);
progressDialog.setMessage(getString(R.string.loading_data));
recyclerView = (RecyclerView) view.findViewById(R.id.search_recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext(), LinearLayoutManager.VERTICAL, false));
SearchManager searchManager = new SearchManager(view.getContext());
searchManager.getAllProfessions(new SearchServiceListener() {
#Override
public void onSuccess(List<SearchDataModel> searchDataModels) {
searchViewAdataper = new SearchViewAdataper(getContext(), searchDataModels);
recyclerView.setAdapter(searchViewAdataper);
progressDialog.dismiss();
}
#Override
public void onFail(Throwable t) {
progressDialog.dismiss();
Toast.makeText(getContext(), R.string.communication_server_problem, Toast.LENGTH_LONG).show();
}
});
return view;
}
}
SearchSectionAdapter adapter: Here it manage all cards items and action click Listener from card item to call a new fragment
NOTE: I will put just setOnClickListener implementation. if necessary all implementation let me know and I can update this question.
holder.mSearchItemImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
ProfessionalManager professionalManager = new ProfessionalManager(v.getContext());
professionalManager.getAllProfessionalByProfessionDescription(singleItem.getDescription(), new ProfessionalServiceListener() {
#Override
public void onSuccess(List<Professional> professionals) {
/*Intent intent = new Intent(v.getContext(), ProfessionalListActivity.class);
v.getContext().startActivity(intent);*/
Fragment fragment = new ProfessionalListFragment();
FragmentTransaction ft = ((FragmentActivity)context)
.getSupportFragmentManager()
.beginTransaction();
ft.replace(R.id.search_recyclerView, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
}
#Override
public void onFail(Throwable t) {
}
});
}
});
you use recyclerView reference here
recyclerView = (RecyclerView) view.findViewById(R.id.search_recyclerView);
again you use recyclerView to replace by fragment that make Problem
ft.replace(R.id.search_recyclerView, fragment);
you need to <fragment> layout to replace it.
I have a fragment containing a RecyclerView and a button. The fragment is brought up on pressing a button (which adds some data) in a previous fragment, and the recycler shows correctly populated, the button works. Then I go back to the previous fragmen, press the button again (adding more data) and the same piece of code brings up the same fragment, but the RecyclerView is unpopulated and the button doesn't work. From reading this question my guess is that I am doing something in my Fragment management - because as soon as I change orientation and the Fragment is recreated, the list shows fine and the button works fine.
So here is the management I'm doing on the fragments - I took it from an example on the internet, but I'm worried it's not correct
First there is a Base class which I make for my fragments:
public class BaseFragment extends Fragment {
private AbstractFragmentCallback mCallback;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (AbstractFragmentCallback) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement " +
AbstractFragmentCallback.class.getCanonicalName());
}
}
/**
* This method replaces the currently shown fragment with a new
fragment of a particular class.
* If a fragment of the required class already shown - does
nothing.
* #param clazz the class of the fragment to show
* #param addToBackStack whether the replacement should be added
to back-stack
* #param args arguments for the newly created fragment (can be
null)
*/
public void replaceFragment(Class<? extends Fragment> clazz,
boolean addToBackStack,
Bundle args) {
mCallback.replaceFragment(clazz, addToBackStack, args);
}
public interface AbstractFragmentCallback {
/**
* Call to this method replaces the currently shown fragment
with a new one
*
* #param clazz the class of the new fragment
* #param addToBackStack whether the old fragment should be
added to the back stack
* #param args arguments to be set for the new fragment
*/
void replaceFragment(Class<? extends Fragment> clazz, boolean addToBackStack,
Bundle args);
}
}
So then my MainActivity implements the BaseFragment.AbstractfragmentCallback so:
public class MainActivity extends AppCompatActivity implements BaseFragment.AbstractFragmentCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(....);
if (null == savedInstanceState) {
replaceFragment(WelcomeFragment.class, false, null);
}
}
// ---------------------------------------------------------------------------------------------
//
// Fragments management
#Override
public void replaceFragment(Class<? extends Fragment> clazz, boolean addToBackStack,
Bundle args) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment newFragment;
try {
// Create new fragment
newFragment = clazz.newInstance();
if (args != null) newFragment.setArguments(args);
} catch (InstantiationException e) {
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
return;
}
if (addToBackStack) {
ft.addToBackStack(null);
}
// Change to a new fragment
ft.replace(R.id.container, newFragment, clazz.getName());
ft.commit();
}
// End of fragments management
//
// ---------------------------------------------------------------------------------------------
}
and when my fragment with the button wants to bring up the list fragment it calls
replaceFragment(ListFragment.class, true, null);
So - to be clear, the ListFragemnt comes up, and all its code fires including recrersating the RecyclerView and repopulating it - I even see all the code in the adapter being called for each item - but the items do not appear in the list
public class ListFragment extends BaseFragment implements ListFragmentMvc.ListViewMvcListener {
private List<MyStuff> stuffList;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
stuffList = new ArrayList<>();
return inflater.inflate(R.layout.list_activity, container, true);
}
#Override
public void onResume() {
super.onResume();
recyclerView = mRootView.findViewById(R.id.recycler_view);
letsGoButton = mRootView.findViewById(R.id.lets_go_button);
letsGoButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Activity activity = getActivity();
if (activity != null) {
getActivity().onBackPressed();
}
}
});
recyclerView.setItemAnimator(new DefaultItemAnimator());
DividerItemDecoration itemDecor = new DividerItemDecoration(context, HORIZONTAL);
recyclerView.addItemDecoration(itemDecor);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(mLayoutManager);
setData(MyApplication.getAllStuffItems());
}
public void setData(List<MyStuff> stuff) {
stuffList = stuff;
mAdapter = new StuffAdapter(stuffList);
recyclerView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
}
}
So, anyone have a clue why this doesn't work until I change orientation on re-entering the listFragment?
Thanks
Can you try to move the code which sets/updates the recyclerView and letsGoButton from the onResume method to onViewCreated method as below:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView = view.findViewById(R.id.recycler_view);
letsGoButton = view.findViewById(R.id.lets_go_button);
letsGoButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Activity activity = getActivity();
if (activity != null) {
getActivity().onBackPressed();
}
}
});
recyclerView.setItemAnimator(new DefaultItemAnimator());
DividerItemDecoration itemDecor = new DividerItemDecoration(context, HORIZONTAL);
recyclerView.addItemDecoration(itemDecor);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(mLayoutManager);
setData(MyApplication.getAllStuffItems());
}
Wow, that was a wild waste of a day.
In the end I had a couple of errors which were pasting over and hiding each other.
The real real reason this wasn't working, I think was because I should have had
return inflater.inflate(R.layout.list_activity, container, false);
instead of
return inflater.inflate(R.layout.list_activity, container, true);
I lied a little in my code because I wasn't really directly returning the result of inflater.inflate... I was calling it (with the wrong parameter) and then returning null.
I guess that will teach me to be more honest in the posting
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.
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 have an activity in which I have Tablayout and have two tab named as "Deal","Story" when I navigate to other activity and again resume to that activity
then that tab was appears which I had viewed earlier,while I want whenever I resumed to that activity always show default tab .How can I DO THAT
code:-
public void init() {
s_oCloginSession = new CLoginSessionManagement(CMainActivity.this);// object creation of Login Session...
setupToolbar();// setting toolbar
// navigation bar code
m_Drawer = (DrawerLayout) findViewById(R.id.drawer_layout);//finding id of drawerlayout
s_drawerToggle = new ActionBarDrawerToggle(
this, m_Drawer, m_Toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
m_Drawer.setDrawerListener(s_drawerToggle);
m_Drawer.setScrimColor(getResources().getColor(android.R.color.transparent));
s_drawerToggle.syncState();
NavigationView m_Navigation = (NavigationView) findViewById(R.id.nav_view);
m_Navigation.setNavigationItemSelectedListener(this);
m_TabLayout = (TabLayout) findViewById(R.id.tab_layout);// finding Id of tablayout
m_TabLayout.addTab(m_TabLayout.newTab().setText("Deals"));// add deal listin tab
m_TabLayout.addTab(m_TabLayout.newTab().setText("Stories"));// add stories tab
m_TabLayout.setTabGravity(TabLayout.GRAVITY_FILL);// setting Gravity of Tab
m_ViewPager = (ViewPager) findViewById(R.id.pager);//finding Id of ViewPager
CDealMainListingPager m_oDealMainScreenPager = new CDealMainListingPager
(getSupportFragmentManager(), m_TabLayout.getTabCount());
m_ViewPager.setAdapter(m_oDealMainScreenPager);// adiing adapter to ViewPager
m_ViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(m_TabLayout));// performing action of page changing
m_TabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
m_ViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
You can create one class named BaseActivity which extends AppCompatActivity. All your activity will now extend to this BaseActivity class instead of AppCompatActivity. So whenever you have not defined onBackPressed it will call it's parent class method and perform it's operations.
public class BaseActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onBackPressed() {
super.onBackPressed();
overridePendingTransition(R.anim.translate, R.anim.left_to_right_simple);
}
}
If you want to customise this method for one class then just need to override this method in that respective class. For other classes it will work same as defined in BaseActivity
Your all activity will be something like this.
public class HomeScreen extends BaseActivity{
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
Make a class, say CommonMethods and put the method into that class:
public class CommonMethods extends AppCompatActivity {
/*This method functions when user press device back button*/
#Override
public void onBackPressed() {
long currentTime = System.currentTimeMillis();
if ((currentTime - lastPressTime) < 2000) {
// Double Press
moveTaskToBack(true);
} else {
Toast.makeText(this, "Press again to exit", Toast.LENGTH_SHORT).show();
lastPressTime = currentTime;
}
}
}
Here, you can make this class extend Activity or AppCompatActivity based on your needs.
Finally, you can make the activity classes which need this feature, extend this CommonMethods class.
You can do this by taking one common class and implement this function in it,
Check below code,
Take one common class for method
//Here I am taking it as common class you can take it as per your choice
CommonClass.java
public class CommonClass
{
public bool manageBackPressed(Activity activity, long lastPressTime)
{
long currentTime = System.currentTimeMillis();
if ((currentTime - lastPressTime) < 2000) {
return true;
} else {
return false;
}
return false;
}
}
Now below check your onBackPressed method in any activity
#Override
public void onBackPressed() {
if(commonClass.manageBackPressed(this, lastPressTime))
{
moveTaskToBack(true);
}
else
{
Toast.makeText(this, "Press again to exit", Toast.LENGTH_SHORT).show();
lastPressTime = System.currentTimeMillis();
}
}
I think your previous thread will also work in background please cancel it when you dont want to update.