Add toolbar dynamically to an abstract activity - android

I have a base activity that all of my activities extend from. This class includes basics like a toolbar and a navigation drawer.
I am looking for a solution that will allow me to override a method in extended activities so I can change the type of toolbar that activity will use.
public abstract class BaseActivity extends AppCompatActivity {
private Toolbar mToolbar;
private FrameLayout mContentFrame;
private ActivityFragment mActivityFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(setLayout());
initViews();
initToolbar();
}
protected int setLayout() {
return R.layout.activity_base;
}
//I want to override this and provide a different toolbar layout!
protected int setToolbarLayout(){
return R.layout.toolbar;
}
protected void initViews() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mContentFrame = (FrameLayout) findViewById(R.id.contentFrame);
}
private void initToolbar() {
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mToolbar.setElevation(10f);
}
}
protected void setContentFragment(ActivityFragment fragment) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(getContentFrame().getId(), fragment).commit();
supportInvalidateOptionsMenu();
this.mActivityFragment = fragment;
setTitle(fragment.getTitle(this));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
public Toolbar getToolbar() {
return mToolbar;
}
public FrameLayout getContentFrame() {
return mContentFrame;
}
public ActivityFragment getActivityFragment() {
return mActivityFragment;
}
I have tried inflating the toolbar after setContentView() and setting the actionbar to it but it appeared with no icons or widgets!

Ok everyone (whoever it concerns) I figured it out. All I had to do was inflate my contentView prior to calling setContentView(). Once I have that inflated I add the inflated toolbar view!
public abstract class BaseActivity extends AppCompatActivity {
private Toolbar mToolbar;
private FrameLayout mContentFrame;
private ActivityFragment mActivityFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(inflateLayout());
initViews();
initToolbar();
}
protected int getLayoutRes(){
return R.layout.activity_base;
}
protected int getToolbarLayout(){
return R.layout.toolbar;
}
private View inflateLayout() {
View contentView = getLayoutInflater().inflate(getLayoutRes(), null, false);
attachToolbarToLayout(getLayoutInflater(), (ViewGroup) contentView);
return contentView;
}
private void attachToolbarToLayout(LayoutInflater inflater, ViewGroup parent){
mToolbar = (Toolbar) inflater.inflate(getToolbarLayout(),parent,false);
parent.addView(mToolbar,0);
}
protected void initViews() {
mContentFrame = (FrameLayout) findViewById(R.id.contentFrame);
}
private void initToolbar() {
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mToolbar.setElevation(10f);
}
}
protected void setContentFragment(ActivityFragment fragment) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(getContentFrame().getId(), fragment).commit();
supportInvalidateOptionsMenu();
this.mActivityFragment = fragment;
setTitle(fragment.getTitle(this));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
public Toolbar getToolbar() {
return mToolbar;
}
public FrameLayout getContentFrame() {
return mContentFrame;
}
public ActivityFragment getActivityFragment() {
return mActivityFragment;
}

Related

Second Activity back press button does not navigate to Fragment that started activity

I am learning android and I am facing a challenge no idea on how to resolve it. That is am unable to go back to the fragment that started the activity. I am opening second activity from fragment but when I press the back button on second activity it does not navigate to the fragment that opened the activity,it shows the home fragment. I have tried this and no success.
and this is the chat fragment that is opening the second fragment
and this is the second activity which if I press back button does not go to chat fragment
and when I press the back button of the second activity this is what am getting. Its showing home fragment content
Here is my Main Activity
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
Fragment fragment;
Toolbar toolbar;
TextView title,txt_profile_contact,txt_profile_name;
ActionBarDrawerToggle toggle;
DrawerLayout drawer;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
notificationRepository=new NotificationRepository(this);
toolbar=findViewById(R.id.toolbar);
title=toolbar.findViewById(R.id.tool_bar_title);
title.setText(R.string.home);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
drawer= findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
assert drawer != null;
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
return;
}
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
doExit(false);
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
Fragment fragment=null;
int idd=R.id.main_fragment_main;
if (id == R.id.menu_chat)
{
title.setText("Chat");
fragment=new ChatFragment();
} else (id == R.id.menu_home) {
title.setText("Home");
fragment=new HomeFragment();
Utils.setIsOnChatActivity(this,false);
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
load_fragment(fragment);
return true;
}
private void load_fragment(Fragment fragment)
{
if(fragment==null)
{
return;
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.fadein, R.anim.fadeout);
toggle.getDrawerArrowDrawable().setColor(getResources().getColor(R.color.white));
toolbar.setBackgroundResource(R.color.colorPrimary);
title.setTextColor(getResources().getColor(R.color.white));
try {
ft.replace(R.id.main_fragment, fragment)
.addToBackStack(null)
.commit();
} catch (IllegalStateException e) {
//ExceptionHandler.logException(e);
}
}
}
and here is the chat fragment
public class ChatFragment extends Fragment implements TutorListAdapter.TutorOnclickListener{
private static final String TAG = ChatFragment.class.getSimpleName();
public ChatFragment() {
// Required empty public constructor
}
FloatingActionButton actionButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.fragment_chat, container, false);
actionButton=view.findViewById(R.id.new_chat_list_btn);
actionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent=new Intent(getActivity(),SecondActivity.class);
startActivity(intent);
mActivity.overridePendingTransition(R.anim.fadein, R.anim.fade_out);
}
});
return view;
}
}
and here is my second activity. NB I have tried even the commented code and does not work
public class SecondActivity extends AppCompatActivity {
Toolbar toolbar;
TextView barText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_subject_details);
toolbar=findViewById(R.id.custom_tool_bar);
barText=toolbar.findViewById(R.id.toolbar_title);
barText.setText("My Activity");
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
}
// #Override
// public boolean onOptionsItemSelected(MenuItem item) {
// if (item.getItemId() == android.R.id.home) {
// onBackPressed();
// return true;
// }
// return super.onOptionsItemSelected(item);
// }
//
// #Override
// public void onBackPressed() {
// Toast.makeText(this, "back pressed?", Toast.LENGTH_SHORT).show();
// if ( getFragmentManager().getBackStackEntryCount() > 0)
// {
// getFragmentManager().popBackStack();
// return;
// }
// super.onBackPressed();
// }
#Override
public boolean onSupportNavigateUp(){
finish();
return true;
}
}
Step-1: Create a custom ViewModelFactory which is basically a Singleton class. This class provides ViewModel.
CustomViewModelProvider.java
public class CommonViewModelProvider extends ViewModelProvider.NewInstanceFactory {
private static CommonViewModelProvider commonViewModelProvider;
private final BottomNavigationViewModel bottomNavigationViewModel;
CommonViewModelProvider(){
bottomNavigationViewModel = new BottomNavigationViewModel();
}
public static CommonViewModelProvider getInstance(){
if (commonViewModelProvider == null)
commonViewModelProvider = new CommonViewModelProvider();
return commonViewModelProvider;
}
#NotNull
#Override
public <T extends ViewModel> T create(#NonNull Class<T> modelClass){
return (T) bottomNavigationViewModel;
}
}
BottomNavigationViewModel.java
public class BottomNavigationViewModel extends ViewModel {
private final MutableLiveData<Integer> currentFragmentId;
public Integer getCurrentFragmentId(){
return currentFragmentId.getValue();
}
public void setCurrentFragmentId(int currFragmentId){
currentFragmentId.setValue(currFragmentId);
}
public BottomNavigationViewModel(){
currentFragmentId = new MutableLiveData<>();
// R.id.navigation_snap is my first fragment. You should replace with your FirstFragment i.e HomeFragment
currentFragmentId.setValue(R.id.navigation_snap);
}
}
Step-2:
You would have a BottomNavigationActivity which has 3 fragments. And 3rd one is your ChatFragment. Inside this activity I am getting current fragment from BottomNavigationViewModel and set it to BottomNavigationView like navView.setSelectedItemId(currentFragment);. So that when you back from SecondActivity to BottomNavigationActivity, ChatFragment will be shown instead of HomeFragment.
BottomNavigationActivity.java
public class BottomNavigationActivity extends AppCompatActivity {
BottomNavigationViewModel bottomNavigationViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bottom_navigation);
//bottomNavigationViewModel = new ViewModelProvider(this).get(BottomNavigationViewModel.class);
CommonViewModelProvider commonViewModelProvider = CommonViewModelProvider.getInstance();
bottomNavigationViewModel = commonViewModelProvider.create(BottomNavigationViewModel.class);
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_snap, R.id.navigation_home, R.id.navigation_chat)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
Integer currentFragment = bottomNavigationViewModel.getCurrentFragmentId();
navView.setSelectedItemId(currentFragment);
}
}
Step-3:
Now you want to open SecondActivity from ChatFragment. Well, in SecondActivity just update currentFragmentId variable of BottomNavigationViewModel, so that when you pressback button, this currentFragment will be shown in BottomNavigationActivity.
SecondActivity.java
public class SecondActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
CommonViewModelProvider commonViewModelProvider = CommonViewModelProvider.getInstance();
BottomNavigationViewModel bottomNavigationViewModel = commonViewModelProvider.create(BottomNavigationViewModel.class); Log.d("tisha==>>","View Model ID inside Second Activity"+ bottomNavigationViewModel.hashCode());
bottomNavigationViewModel.setCurrentFragmentId(R.id.navigation_chat);
}
}
NOTE: Whenever you want to open BottonNavigationActivity make sure you have set correct fragment which will be open first. Use below code to set currentFragment to ViewModel which is already done in SecondActivity.
CommonViewModelProvider commonViewModelProvider = CommonViewModelProvider.getInstance();
BottomNavigationViewModel bottomNavigationViewModel = commonViewModelProvider.create(BottomNavigationViewModel.class); Log.d("tisha==>>","View Model ID inside Second Activity"+ bottomNavigationViewModel.hashCode());
bottomNavigationViewModel.setCurrentFragmentId(R.id.navigation_chat);

Android home button with drawer navigation stops to work with rotation screen

I have a main activity with navigation drawer and a button to load fragment.
When the main ativity is launched I load the MainFragment.
In this moment all works well. The hamburger icon is showing and my Main fragment was loaded.
Next, I click a button and load a secondFragment. After I load the second fragment, I can use the backbutton and homebutton to come back to main activity without problems.
When I am with second fragment loaded and I make a rotation screen, the back button continues to work well, but the home button disappears and hamburger icon appears.
What am i doing wrong?
public class MainActivity extends AppCompatActivity {
private ActionBarDrawerToggle actionBarDrawerToggle;
private DrawerLayout drawerLayout;
private Toolbar toolbar;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String mSubTitle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initNavigationDrawer();
if (savedInstanceState != null) {
return;
}
MainActivityFragment mainFragment = new MainActivityFragment();
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
//transaction.replace(R.id.fragment_container, firstFragment);
transaction.replace(R.id.fragment_container, mainFragment, "princ");
transaction.commit();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Only handle with DrawerToggle if the drawer indicator is enabled.
if (actionBarDrawerToggle.isDrawerIndicatorEnabled() &&
actionBarDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle your other action bar items...
return super.onOptionsItemSelected(item);
}
}
public Fragment getCurrentFragment(){
FragmentManager frgmgr = getSupportFragmentManager();
return frgmgr.findFragmentById(R.id.fragment_container);
}
#Override
public void onBackPressed() {
if (drawerLayout != null) {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START);
return;
}
}
if ((getCurrentFragment() instanceof MainFragment)) {
finish();
} else if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else super.onBackPressed();
}
public void initNavigationDrawer() {
NavigationView navigationView = (NavigationView) findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
FragmentManager frgmgr = getSupportFragmentManager();
FragmentTransaction transaction = frgmgr.beginTransaction();
Fragment cur_frag;
// Handle navigation view item clicks here.
int id = menuItem.getItemId();
switch (id) {
case R.id.home:
cur_frag = frgmgr.findFragmentById(R.id.fragment_container);
if (!(cur_frag instanceof MainActivityFragment)) {
MainActivityFragment frag = new MainActivityFragment();
transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
transaction.replace(R.id.fragment_container, frag);
transaction.commit();
break;
}
drawerLayout.closeDrawers();
break;
case R.id.logout_drw:
finish();
}
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
});
View header = navigationView.getHeaderView(0);
TextView tv_email = (TextView) header.findViewById(R.id.tv_email);
tv_email.setText("Agendamento");
drawerLayout = (DrawerLayout) findViewById(R.id.drawer);
mTitle = mDrawerTitle = getTitle();
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {
#Override
public void onDrawerClosed(View v) {
super.onDrawerClosed(v);
}
#Override
public void onDrawerOpened(View v) {
super.onDrawerOpened(v);
}
};
drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
if (toolbar != null) {
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
int i=getSupportFragmentManager().getBackStackEntryCount();
if ((i > 0) || (!(getCurrentFragment() instanceof MainActivityFragment))) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true); // show back button
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
actionBarDrawerToggle.syncState();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
drawerLayout.openDrawer(GravityCompat.START);
}
});
}
}
});
}
}
}
Main Fragment:
public class MainFragment extends Fragment {
public MainFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_main, container, false);
Button butCons= (Button) view.findViewById(R.id.butcons);
butCons.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
SecundaryFrag frag = new SecundaryFragFrag();
// Add the fragment to the 'fragment_container' FrameLayout
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
transaction.replace(R.id.fragment_container, frag);
transaction.addToBackStack(null);
transaction.commit();
}
});
return view;
}
}
Secondary Fragment:
public class SecundaryFrag extends Fragment{
public SecundaryFrag() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_consulta_ag, container, false);
return view;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
((MainActivity)getActivity()).onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
After Rotation:
Main activty with main fragment:
Before Rotation:
I believe it is related to the fact that the view is recreated after the orientation change. I would take a closer look to the onCreate() from the MainActivity in particular when the
if (savedInstanceState != null) {
return;
}
is triggered.
One option is to retain the fragments and restoring them onCreate. Also you could turn off the recreation by catching the orientation and handle it yourself in the application, you can see here both options explained developer.android.com/guide/topics/resources/

nested fragment throwing null

The end goal is to click from a list view stored in one fragment,
open another fragment that has a nested fragments view AnswerFragment,
here the nested fragments should consist of two fragments, top portion being the question text from the list and the bottom half being the answer. Right now I've managed to pull off the communication bit of passing the question text from the list to the single question fragment (which should be stored in the top half of the answer fragment) However it's inflating the single question layout over the answer fragment like this SingleQuestionFragment
.
public class MainActivity extends AppCompatActivity implements AllQsFragment.Communicator {
private DrawerLayout mDrawer;
private Toolbar toolbar;
private NavigationView mNVDrawer;
private ActionBarDrawerToggle drawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Set a Toolbar to replace the ActionBar.
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerToggle = setupDrawerToggle();
mDrawer.setDrawerListener(drawerToggle);
//Find our drawer view
mNVDrawer = (NavigationView) findViewById(R.id.nvView);
//Setup drawer view
setupDrawerContent(mNVDrawer);
}
private ActionBarDrawerToggle setupDrawerToggle() {
return new ActionBarDrawerToggle(this, mDrawer, toolbar, R.string.drawer_open, R.string.drawer_close);
}
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
selectDrawerItem(menuItem);
return true;
}
});
}
public void selectDrawerItem(MenuItem menuItem) {
//Creat a new fragment and specify the planet to show based on
//position
Fragment fragment = null;
Class fragmentClass;
switch (menuItem.getItemId()) {
case R.id.nav_first_fragment:
fragmentClass = AllQsFragment.class;
break;
default:
fragmentClass = AllQsFragment.class;
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
//Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flContent, fragment).addToBackStack("addedToBackStack").commit();
//Highlight the selected item, update the title, and close the drawer
menuItem.setChecked(true);
setTitle(menuItem.getTitle());
mDrawer.closeDrawers();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
//The action bar home/up action should open or close the drawer
switch (item.getItemId()) {
case android.R.id.home:
mDrawer.openDrawer(GravityCompat.START);
return true;
}
if (drawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
//Sync the toggle state after onRestoreInstanceState has occurred
drawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//Pass any configuration change to the drawer toggles
}
#Override
public void sendText(String data) {
SingleQuestionFragment questionFragment = (SingleQuestionFragment) getSupportFragmentManager().findFragmentByTag("fragmentQ");
if (questionFragment != null) {
questionFragment.changeText(data);
} else {
SingleQuestionFragment fragment = new SingleQuestionFragment();
Bundle args = new Bundle();
args.putString("text", data);
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.flContent, fragment)
.addToBackStack(null).commit();
fragment.sentText();
}
}
}
fragment_answer
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.victor.nattest5.AnswerFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="#+id/q_fragment">
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="#+id/a_fragment">
</FrameLayout>
</LinearLayout>
AnswerFragment
public class AnswerFragment extends Fragment {
public AnswerFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
insertNestedFragment();
return inflater.inflate(R.layout.fragment_answer, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
private void insertNestedFragment() {
Fragment childQFragment = new SingleQuestionFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.q_fragment, childQFragment,
"fragmentQ").commit();
Fragment childAFragment = new SingleAnswerFragment();
FragmentTransaction transaction1 = getChildFragmentManager().beginTransaction();
transaction1.add(R.id.a_fragment, childAFragment, "fragmentA").commit();
}
public static final AnswerFragment newInstance() {
AnswerFragment frag = new AnswerFragment();
return frag;
}
}
SingleQuestionFragment
public class SingleQuestionFragment extends Fragment {
TextView questionTxt;
String stringtext;
public SingleQuestionFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_single_question, container, false);
questionTxt = (TextView) v.findViewById(R.id.textView_q);
return v;
}
public static final SingleQuestionFragment newInstance() {
SingleQuestionFragment frag = new SingleQuestionFragment();
return frag;
}
public void changeText(String data) {
questionTxt.setText(data);
}
public void sentText() {
new BackGroundTask().execute();
}
private class BackGroundTask extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... strings) {
Bundle b = getArguments();
stringtext = b.getString("text");
return null;
}
protected void onPostExecute(String result){
changeText(stringtext);
}
}
}
When I run this with the debugger, the app runs without crashing. However, it shows this line is null ->
SingleQuestionFragment questionFragment = (SingleQuestionFragment) getSupportFragmentManager().findFragmentByTag("fragmentQ");
I know what null means, I just don't understand how to fix this problem. Somewhere in my code I think I'm inflating an extra layout or possibly inflating the wrong container.
It's hard to offer any suggestions because your app is complex and not all of the code is posted. It's also not clear whether any of the posted code includes changes you've made to try and work around the problem. For example, I don't understand the need for BackGroundTask. There is no reason to perform that processing in a background thread. Did you do this as a workaround to add some delay to the processing?
You didn't post the code that calls MainActivity.sendText(), or explain what causes it to be called.
If I understand your post correctly, in sendText(), the call to findFragmentByTag() is returning null and that is an error. Are you expecting to find the SingleQuestionFragment added in AnswerFragment? If so, you won't find it because you are searching the fragments held by the manager of MainActivity only. The search does not include fragments held by the managers of child fragments. In other words, the search does not recursively search the fragment tree.

Android Back Arrow icon on ActionBar not working

For some reason this activity has the back arrow in the actionbar, but when it is clicked it has no reaction, doesn't even seen to recognize the click. I have other activities that are similar that work fine though. Here is the code with some stuff removed:
public class LanguageActivity extends ActionBarActivity {
private static final String TAG = "LanguageActivity";
#InjectView(R.id.listView)
RecyclerView mRecyclerView;
#State
String selectedLang;
LangViewHolder selectedHolder = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Icepick.restoreInstanceState(this, savedInstanceState);
setContentView(R.layout.recyclerview);
ButterKnife.inject(this);
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setTitle(R.string.ad_title_settings_lang);
selectedLang = PreferencesFacade.getInstance().getCurrentLang();
mRecyclerView.setLayoutManager(new TrueWrapContentLinearLayoutManager(this));
List<Pair<String, String>> langList = new LinkedList<>();
langList.add(Constants.Languages.US);
langList.add(Constants.Languages.LATIN_AMERICA_SPANISH);
mRecyclerView.setAdapter(new RecycleViewMappedArrayAdapter(R.layout.view_language_item, new LangViewHolder(mRecyclerView), langList));
}
#Override
protected void onSaveInstanceState(Bundle outState) {
Icepick.saveInstanceState(this, outState);
super.onSaveInstanceState(outState);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void finish() {
super.finish();
PreferencesFacade.getInstance().setCurrentLang(selectedLang);
Log.v(TAG, "Finishing?");
}
public class LangViewHolder extends RecycleViewMappedArrayAdapter.ViewHolder<Pair<String, String>>{
...
}
}
Manifest snippet:
<activity android:name=".activities.LanguageActivity"
android:parentActivityName=".activities.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activities.MainActivity"/>
</activity>
This seems to be working for me:
Toolbar tBar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(tBar); // sets the Toolbar as the actionbar
tBar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp));
tBar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed(); // calls the System onBackPressed method
}
});
Update:
getDrawable(int id) is depreciated so you should change this line of code:
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= Build.VERSION_CODES.LOLLIPOP){
tBar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp, getApplicationContext().getTheme()));
} else {
tBar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp));
}
why don't You extend AppCompatActivity(i think actionbaractivity is deprecated...)
?
and
Toolbar toolbar = (Toolbar) findViewById(R.id.the_id);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//try this instead
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});

Implement back navigation with DrawerLayout and AppCompatActivity without DrawerToggle

I've been searching and thinking how to implement the desire behaviour that I want when switching back and forth between fragments when using a Navigation Drawer. Actually the documentation says:
When using fragments in your app, individual FragmentTransaction objects may represent context changes that should be added to the back stack. For example, if you are implementing a master/detail flow on a handset by swapping out fragments, you should ensure that pressing the Back button on a detail screen returns the user to the master screen
So in my app I have a MainActivity that controls everything and a navigation layout within you can change between predefined options. This is the view when you launch the app
When you click on an item in the navigation drawer it opens a new fragment that replaces the main_content as follows:
At this point the behaviour is the correct one, so if you want to change the options you need to open the navigation drawer again to toggle between the menu options.
This is the Main Activity (notice that there is no Drawer Toggle)
MainActivity.java
public class MainActivity extends AppCompatActivity {
ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout drawerLayout;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSnackBarView = findViewById(R.id.myCoordinatorLayout);
setToolbar(); // Set Toolbar como action bar
if (savedInstanceState != null) {
mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
mFromSavedInstanceState = true;
}
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
if (navigationView != null) {
setupDrawerContent(navigationView);
}
drawerTitle = getResources().getString(R.string.app_name);
if (savedInstanceState == null) {
selectItem(drawerTitle, mCurrentSelectedPosition);
}
}
private void setToolbar() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final ActionBar ab = getSupportActionBar();
if (ab != null) {
// Poner ícono del drawer toggle
ab.setHomeAsUpIndicator(R.drawable.ic_menu);
ab.setDisplayHomeAsUpEnabled(true);
}
}
private void setupDrawerContent(final NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
// Marcar item presionado
menuItem.setChecked(true);
// Crear nuevo fragmento
String title = menuItem.getTitle().toString();
int id = menuItem.getItemId();
selectItem(title, id);
return true;
}
}
);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!drawerLayout.isDrawerOpen(GravityCompat.START)) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
private void selectItem(String title, int id) {
Bundle args = new Bundle();
args.putString(PlaceholderFragment.ARG_SECTION_TITLE, title);
Fragment fragment = PlaceholderFragment.newInstance(title);
fragment.setArguments(args);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager
.beginTransaction()
.replace(R.id.main_content, fragment)
.commit();
switch (id) {
case R.id.nav_localizacion:
//Snackbar.make(mSnackBarView, R.string.menu_localization, Snackbar.LENGTH_SHORT).show();
mCurrentSelectedPosition = 0;
LocalizacionFragment fragment_localizacion = new LocalizacionFragment();
// fragmentManager = getSupportFragmentManager();
Snackbar.make(mSnackBarView, R.string.menu_localization, Snackbar.LENGTH_SHORT).show();
fragmentManager
.beginTransaction()
.replace(R.id.main_content, fragment_localizacion)
.commit();
break;
case R.id.nav_productos:
Snackbar.make(mSnackBarView, R.string.menu_productos, Snackbar.LENGTH_SHORT).show();
mCurrentSelectedPosition = 1;
fragmentManager
.beginTransaction()
.replace(R.id.main_content, fragment)
.commit();
break;
case R.id.nav_consejos:
Snackbar.make(mSnackBarView, R.string.menu_consejos, Snackbar.LENGTH_SHORT).show();
mCurrentSelectedPosition = 3;
ConsejosFragment fragment_consejo = new ConsejosFragment();
fragmentManager
.beginTransaction()
.replace(R.id.main_content, fragment_consejo)
.commit();
break;
default:
break;
}
drawerLayout.closeDrawers(); // Cerrar drawer
setTitle(title); // título actual
}
}
I don't use the hamburger icon because it hides under the Navigation Layout, but here is the thing. When you click on "Recetas" in the recycle view it open a new fragment (replace) but now I want to show the up caret icon and give proper back navigation to my app.
Here is the code of the "Consejos" fragment class
Consejos.java
public class ConsejosFragment extends Fragment {
RecyclerView mRecycler;
ConsejosAdapter mAdapter;
FragmentActivity mActivity;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivity = (FragmentActivity) activity;
setRetainInstance(true);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
List items = new ArrayList();
items.add(new ConsejosInfo("Recetas", R.drawable.icon_recetas));
/* Inflamos el layout */
View v = inflater.inflate(R.layout.consejos_layout_recycler, container, false);
/* Obtenemos el Recycle */
mRecycler = (RecyclerView) v.findViewById(R.id.recycler_consejos);
/* Creamos el adaptador */
mAdapter = new ConsejosAdapter(mActivity, items);
/* Set click en adapter */
return v;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mRecycler.setHasFixedSize(true);
mRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecycler.setAdapter(mAdapter);
}
}
And this is the adapter that the Recyclerview use and handles the click on the item inside:
Adapter.java
public class ConsejosAdapter extends RecyclerView.Adapter<ConsejosAdapter.ConsejosViewHolder> {
private List<ConsejosInfo> _items = new ArrayList<ConsejosInfo>();
private final FragmentActivity mActivity;
private Context context;
public ConsejosAdapter(FragmentActivity mActivity, List<ConsejosInfo> items) {
this._items = items;
this.mActivity = mActivity;
}
#Override
public int getItemCount() {
return _items.size();
}
#Override
public ConsejosViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.cardview_consejos, viewGroup, false);
return new ConsejosViewHolder(v);
}
#Override
public void onBindViewHolder(ConsejosViewHolder viewHolder, int position) {
viewHolder.imagen.setImageResource(_items.get(position).get_imagen());
viewHolder.nombre.setText(_items.get(position).get_nombre());
}
public class ConsejosViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public ImageView imagen;
public TextView nombre;
public ConsejosViewHolder(final View itemView) {
super(itemView);
imagen = (ImageView) itemView.findViewById(R.id.consejos_imagen);
nombre = (TextView) itemView.findViewById(R.id.consejos_nombre);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
RecetasFragment recetasFragment = new RecetasFragment();
FragmentManager fragmentManager = mActivity.getSupportFragmentManager();
fragmentManager
.beginTransaction()
.replace(R.id.main_content, recetasFragment)
.addToBackStack(null)
.commit();
}
}
}
In the Consejos Adapter I added to backstack the fragment before calling the new fragment (inside fragment) and that changes the behaviour of the back button, so before this if you press the back button is closes the app but now it takes you to the Consejos fragment, but now I want to add the up caret and make the exactly same operation as when you click the back button but I don't know how to achieve it.
Please feel free to ask for more code
Thank you very much
I will give you the full answer:
We will use the interfaces to communicate with the MainActivity from RecetasFragment so we can enable and disable navigation back button.
RecetasFragment class:
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by hema on 8/19/2015.
*/
public class RecetasFragment extends Fragment {
private CommunicateWithActivity mWithActivity;
public RecetasFragment() {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mWithActivity = (CommunicateWithActivity) activity; // MainActivity must implement CommunicateWithActivity interface.
mWithActivity.enableNavigationBack(true); // We enable navigation back here.
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement CommunicateWithActivity");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recetas, container, false);
}
#Override
public void onDestroy() {
super.onDestroy();
mWithActivity.enableNavigationBack(false); // We disable navigation back here, restore menu icon.
}
public interface CommunicateWithActivity {
void enableNavigationBack(boolean enable);// we will implement this method in MainActivity class.
}
}
And in MainActivity class we will implement CommunicateWithActivity interface, Modify your MainActivity class (only required modifications):
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends AppCompatActivity implements RecetasFragment.CommunicateWithActivity {
private Toolbar mToolbar;
private DrawerLayout drawerLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
mToolbar.setNavigationIcon(R.drawable.ic_menu);
mSnackBarView = findViewById(R.id.myCoordinatorLayout);
if (savedInstanceState != null) {
mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
mFromSavedInstanceState = true;
}
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
if (navigationView != null) {
setupDrawerContent(navigationView);
}
drawerTitle = getResources().getString(R.string.app_name);
if (savedInstanceState == null) {
selectItem(drawerTitle, mCurrentSelectedPosition);
}
}
private void setupDrawerContent(final NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
// Marcar item presionado
menuItem.setChecked(true);
// Crear nuevo fragmento
String title = menuItem.getTitle().toString();
int id = menuItem.getItemId();
selectItem(title, id);
return true;
}
}
);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!drawerLayout.isDrawerOpen(GravityCompat.START)) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
private void selectItem(String title, int id) {
Bundle args = new Bundle();
args.putString(PlaceholderFragment.ARG_SECTION_TITLE, title);
Fragment fragment = PlaceholderFragment.newInstance(title);
fragment.setArguments(args);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager
.beginTransaction()
.replace(R.id.main_content, fragment)
.commit();
switch (id) {
case R.id.nav_localizacion:
//Snackbar.make(mSnackBarView, R.string.menu_localization, Snackbar.LENGTH_SHORT).show();
mCurrentSelectedPosition = 0;
LocalizacionFragment fragment_localizacion = new LocalizacionFragment();
// fragmentManager = getSupportFragmentManager();
Snackbar.make(mSnackBarView, R.string.menu_localization, Snackbar.LENGTH_SHORT).show();
fragmentManager
.beginTransaction()
.replace(R.id.main_content, fragment_localizacion)
.commit();
break;
case R.id.nav_productos:
Snackbar.make(mSnackBarView, R.string.menu_productos, Snackbar.LENGTH_SHORT).show();
mCurrentSelectedPosition = 1;
fragmentManager
.beginTransaction()
.replace(R.id.main_content, fragment)
.commit();
break;
case R.id.nav_consejos:
Snackbar.make(mSnackBarView, R.string.menu_consejos, Snackbar.LENGTH_SHORT).show();
mCurrentSelectedPosition = 3;
ConsejosFragment fragment_consejo = new ConsejosFragment();
fragmentManager
.beginTransaction()
.replace(R.id.main_content, fragment_consejo)
.commit();
break;
default:
break;
}
drawerLayout.closeDrawers(); // Cerrar drawer
setTitle(title); // título actual
}
#Override
public void enableNavigationBack(boolean enable) {
if(enable) {
// We enable the navigation back button here
mToolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// On navigation back button clicked.
if(getSupportFragmentManager().getBackStackEntryCount() > 0) { // Check if there is fragments in BackStack.
getSupportFragmentManager().popBackStack(); // PopBackStack.
} else {
// You can implement this part as you want.
return;
}
}
});
} else {
mToolbar.setNavigationIcon(R.drawable.ic_menu);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(drawerLayout != null) {
drawerLayout.openDrawer(Gravity.LEFT);
}
}
});
}
}
}
Please let me know if there is something you don't understand.

Categories

Resources