I am just starting with android studio, so excuse me for any mistakes. I am trying to switch the language of the app by using spinner menu. I have come over some methods to do this, but I was trying to simplify it and see if I can make this just by using onOptionsItemSelected method. Everything works fine and the language changes in the app, but only if I load another fragment in this activity. I was looking for a solution how to refresh the activity so that the user doesn't have to click any other button to see that the language has changed. I came up with a solution to finish the activity and make the intent to start it again, but here the problem starts. The activity restarts but it shows the default fragment which I assigned on the onCreate method. I don't know how to make it load the fragment which the user was currently seeing. It would be great if I could make the activity start loading from the onResume method, instead of onCreate again, I think it would show the current fragment. Is it even possible to do this? Is there any other easy way to make it show the current fragment with the new language? Maybe there's no easy way and I should start all over again? Please help me. This is what I've tried:
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
Configuration configuration = new Configuration();
Intent intent = new Intent();
switch (item.getItemId()){
case R.id.action_polski:
Locale localePl = new Locale("pl");
Locale.setDefault(localePl);
configuration.locale = localePl;
getBaseContext().getResources().updateConfiguration(configuration,getBaseContext().getResources().getDisplayMetrics());
finish();
startActivity(new Intent(this, MainActivity.class));
overridePendingTransition(0, 0);
break;
case R.id.action_english:
Locale localeEn = new Locale("en");
Locale.setDefault(localeEn);
configuration.locale = localeEn;
getBaseContext().getResources().updateConfiguration(configuration,getBaseContext().getResources().getDisplayMetrics());
finish();
startActivity(new Intent(this, MainActivity.class));
overridePendingTransition(0, 0);
break;
}
return true;
}
Unfortunately I can't just refresh the fragment. The entire activity has to be refreshed because otherwise the navigation drawer doesn't change the language, it stays in the previous language.
Edit: This is the code in onCreate, I add the fragment at the end of this code. But it's the home fragment, so whenever I "refresh" the activity with my method it loads the same fragment.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
hideSystemUI();
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
navigationView.bringToFront();
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new HomeFragment()).commit();
navigationView.setCheckedItem(R.id.nav_home);
}
}
Instead of start new with same Activity you should call recreate and inside onCreate method you have to check savedInstanceState == null before init default fragment
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
Configuration configuration = new Configuration();
Intent intent = new Intent();
switch (item.getItemId()){
case R.id.action_polski:
Locale localePl = new Locale("pl");
Locale.setDefault(localePl);
configuration.locale = localePl;
getBaseContext().getResources().updateConfiguration(configuration,getBaseContext().getResources().getDisplayMetrics());
recreate()
break;
case R.id.action_english:
Locale localeEn = new Locale("en");
Locale.setDefault(localeEn);
configuration.locale = localeEn;
getBaseContext().getResources().updateConfiguration(configuration,getBaseContext().getResources().getDisplayMetrics());
recreate()
break;
}
return true;
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
// init default fragment
}
}
Related
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_create: //run NoteActivity in new note mode
startActivity(new Intent(this, NoteActivity.class));
break;
case R.id.action_theme:
setTheme(R.style.Theme2);
setContentView(R.layout.activity_main);
Intent i = getIntent();
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
// TODO: show settings activity
break;
}
return super.onOptionsItemSelected(item);
}
I have a menu item at the top of my activity. I would like to use it to change the theme when pressed. I want to do this after the user has started the program and it will be eventually used to cycle through a bunch of different themes! Right now I just want to get it to work with one. How can I do this?
My Answer
Main Activity
SharedPreferences pref;
SharedPreferences.Editor editor;
int check;
int newcheck;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pref = getApplicationContext().getSharedPreferences("test", Context.MODE_PRIVATE);
check = pref.getInt("x", 0);
if(check == 0){
setTheme(R.style.AppTheme);
}else{
setTheme(R.style.Theme2);
}
setContentView(R.layout.activity_main);
noteActivity = new NoteActivity();
mListNotes = (ListView) findViewById(R.id.main_listview);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_create: //run NoteActivity in new note mode
startActivity(new Intent(this, NoteActivity.class));
break;
case R.id.action_theme:
pref = getApplicationContext().getSharedPreferences("test", Context.MODE_PRIVATE);
editor = pref.edit();
newcheck = pref.getInt("x",0);
if(newcheck == 0) {
newcheck = 1;
}else if(newcheck == 1){
newcheck = 0;
}
editor.clear();//clears the editor to avoid errors
editor.putInt("x",newcheck);//add in new int
editor.commit();//commit
//restart the activity
Intent i = getIntent();
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
finish();//close activity - avoid crash
startActivity(i);//start activity
//TODO show settings activity
break;
}
return super.onOptionsItemSelected(item);
}
So as far as I've understood your problem, you might consider thinking of taking a parent Activity and set a Fragment in there so that you can change the theme of your Fragment where the control of changing the theme is from your parent Activity. So here's how you can achieve this behaviour.
Get a fragment container in your Activity and launch your Fragment in that container in the onCreate function of your Activity.
As you're having a menu option button to decide which theme to be deployed in the Fragment you might consider replacing your Fragment again by doing another fragment transaction when your menu option is clicked.
You might consider saving the selected theme in SharedPreferences so that each time your Fragment launches, you can set the theme properly by setting it in your onCreateView function of your Fragment after reading the selected theme from your SharedPreferences.
Now if you're thinking of how you can set a theme in your Fragment then this post might help you in this regard. I'm copying the code from there for your convenience.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// create ContextThemeWrapper from the original Activity Context with the custom theme
final Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), R.style.yourCustomTheme);
// clone the inflater using the ContextThemeWrapper
LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);
// inflate the layout using the cloned inflater, not default inflater
return localInflater.inflate(R.layout.yourLayout, container, false);
}
I hope you get the idea already. Please let me know if there's anything else you need clarification about.
My problem is almost the same as this Stop AsyncTask in Fragments when Back Button is pressed
But I want to stop my AsyncTask when the back arrow is clicked. I have a code in stoping asynctask and it works when I implemented it in another way. I tried what I researched so far but I still got errors. Please help me with this.
I tried this code
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id=item.getItemId();
if(id==android.R.id.home)
{
Intent returnIntent = new Intent();
returnIntent.putExtra("flag",userid);
setResult(Activity.RESULT_OK,returnIntent);
finish();
return true;
}}
UPDATED:
I am using this code to go to another fragment.
Fragment2 fragmentChild = new Fragment2 ();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.content, fragmentChild);
transaction.addToBackStack(null);
transaction.commit();
I have no problem in my backtrack when I go to another fragment. Then I'm using this code (getSupportActionBar().setDisplayHomeAsUpEnabled(true)) in my (Drawer.java) to show the back arrow. Now I want to add event when I clicked back arrow.
EDIT: (Drawer.java)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
final View.OnClickListener originalToolbarListener = toggle.getToolbarNavigationClickListener();
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
toggle.setDrawerIndicatorEnabled(false);
toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getSupportFragmentManager().popBackStack();
}
});
} else {
toggle.setDrawerIndicatorEnabled(true);
toggle.setToolbarNavigationClickListener(originalToolbarListener);
}
}
});
If you properly setup the action bar, then you should be able to achive that with the following:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// Add the code to stop the task
break;
}
return super.onOptionsItemSelected(item);
}
EDIT: After you are able to handle the back button event, you can add the code to close the tasks in fragments. First of all, I created an interface that is implement by all fragments that should be able to close this tasks.
public interface TaskCancelFragment {
void cancelTask();
}
The implementation in fragments should look something like this:
#Override
public void cancelTask() {
//Add the code to cancel the task
Toast.makeText(getContext(), "The task is canceled", Toast.LENGTH_SHORT).show();
}
The final step is to send the event from activity to fragment. Here I will assume some things since I don't have access to your code to see how you add/find the fragments, but fortunately this doesn't matter so much and is easy to change. In addition to the initial answer, I created a new method in activity to find the current fragment and close the task.
private void cancelTasks() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.placeholder);
if (fragment instanceof TaskCancelFragment) {
((TaskCancelFragment) fragment).cancelTask();
}
}
And in the end, the case android.R.id.home looks like this:
case android.R.id.home:
cancelTasks();
onBackPressed(); // I think that you want to close the activity too
break;
In my app, am using a navigation drawer (in Fragment A) to navigate to fragments:
public void displayView(int viewId){
Fragment fragment = null;
String title = getString(R.string.app_name);
switch (viewId) {
case R.id.nav_menu:
fragment = new MenuFragment();
title = getString(R.string.menu_title);
viewIsAtHome = false;
break;
case R.id.nav_reservation:
fragment = new ReservationFragment();
title = getString(R.string.reservation_title);
viewIsAtHome = false;
break;
...
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.commit();
}
// set the toolbar title
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(title);
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
}
displayView() is called in onNavigationItemSelected:
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
displayView(item.getItemId());
return true;
}
Now, in ReservationFragment I am displaying a list of reservations and a FloatingActionButton to start Activity B where the user can add a reservation if there are no reservations. When the user is done adding a reservation, I want to display it in the Reservation fragment. This requires me to "go back" to the Fragment.How do I accomplish this since Activity B knows nothing about Activity A?
What I've tried:
I tried creating a method in Activity A like this:
public void navigateToFragment(int viewId) {
displayView(R.id.nav_reservation);
}
and then called this method from Activity B:
saveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new MainActivity().navigateToFragment(R.id.nav_reservation);
//MainActivity is Activity A
}
});
the app crashes due to a nullPointerException in displayView() from the line:
String title = getString(R.string.app_name);
This isn't surprising since am creating a new MainActivity object that knows nothing about the previous state of the Activity, right?
This question mirrors my problem but is based on Settings so I can't really use the answer in my case.
How do I accomplish this task?
There are three quick methods that come to my mind. First you can start activityB with startActivityForResult and handle the result in activityA after user does what he wants in activityB. Second you can set activityA as singleTop and before finishing activityB you can startActivityA with clearTop an intent flag called clear_top(https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TOP).
Last but not the least, you can connect two activity by binding service in both activities and communicate via that service that you bound.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//identify object
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
**title = (TextView)findViewById(R.id.theTitle);
Intent intent = getIntent();
String Title = intent.getExtras().getString("name");
title.setText(Title);**
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
// Handle the camera action
} else if (id == R.id.nav_gallery) {
Intent intent = new Intent(this, addCounter.class);
startActivity(intent);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
When nav_gallery = true, it brings me to activity2 which has the following code:
public void addOk(){
String sendName = name.getText().toString();
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("name", sendName);
startActivity(intent);
}
I want to send the information from activity2 back to the main activity. Is my getIntent() in the wrong place?
Your getIntent() method is inside the onCreate method.
But onCreate is called only once, at creation. And if the MainActivity is still in the stack, there is no reason why onCreate() would be called again.
You should try to insert your code inside onResume() or onStart().
I have setup a new project with the template implementation of Navigation Drawer Fragment and a MainActivity.
It provides me with the following relevant methods:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = getIntent();
token = intent.getStringExtra(EXTRA_TOKEN);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.activityMain = this;
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
My MainActivity is started by a splash activity which gets a saved access token via the EXTRA_TOKEN.
This is the override of the Navigation Drawer item select listener in the MainAcitivity:
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
onSectionAttached(position + 1);
switch(position) {
case 0:
fragmentManager.beginTransaction()
.replace(R.id.container, FeedFragment.newInstance(token, ""))
.commit();
break;
case 1:
fragmentManager.beginTransaction()
.replace(R.id.container, PeopleFragment.newInstance("", ""))
.commit();
break;
case 2:
if(qbloggedin) {
fragmentManager.beginTransaction()
.replace(R.id.container, MessagesFragment.newInstance(token, ""))
.commit();
}
break;
default:
break;
}
}
It starts three different fragments depending on which item is selected in the NavDrawer. While instantiating the new fragments, the token string is passed into its constructor, which is saved in the fragment's class for further use.
On the first start of the App however, it seems that onNavigationDrawerItemSelected is called before onCreate! This results me passing a null value token into the fragments, causing them to be all messed up.
How is this possible? As I understand it, the NavigationDrawerFragment should not have been setup yet!
I set breakpoints on both onCreate and on onNavigationDrawerItemSelected switch position = 0. onNavigationDrawerItemSelected is indeed hit before onCreate.
How can I make sure to get the token first before trying to handle the onNavigationDrawerItemSelected?
Any help would be appreciated.
I believe I figured this out as it was happening to me for anyone who searches this and can't find the answer.
If you use the Android Studio DrawerActivity then there is boilerplate code that they create for you. In this code in the activity_main.xml or whichever XML your DrawerActivity sets as its' content view, there is a tag.
When setContentView() is called in onCreate(), this fragment is automatically created and so technically onCreate() is still being called first but then the onNavigationDrawerItemSelected() method is called before anything else in create. Since setContentView is typically kept up top, this causes problems when trying to store the state of the fragments in your drawer.
Simply move any code that checks for savedInstanceBundle above setContentView() and it will fix the problem.
Example with comments:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// THIS IS WHERE YOU CHECK FOR SAVED INSTANCE
// Check for frag
if (savedInstanceState != null) {
Log.i(TAG, "Get QuestionDayFragment");
mQuestionDaysFragment = (QuestionDaysFragment) getSupportFragmentManager().getFragment(savedInstanceState, QUESTION_DAY_FRAGMENT);
}
// View injection
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
// THIS IS WHERE THE CODE WAS BEFORE
// THIS WOULD BE CALLED AFTER onNavigationDrawerItemSelected()
// Singleton injection
LifeboxApplication.graph().inject(this);
// Toolbar
setSupportActionBar(mToolbar);
// FB
uiHelper = new UiLifecycleHelper(this, callback);
uiHelper.onCreate(savedInstanceState);
// Drawer
mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout));
}
You could move the intent to a constructor and save your tokens there like so:
Intent i;
......
public FragmentConstructor() {
i = getIntent();
token = intent.getStringExtra(EXTRA_TOKEN);
}
What I had to do to make it work was to check if the page has loaded before executing onNavigationDrawerItemSelected
private Boolean loaded=false;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Your code here
this.loaded=true;
}
public void onNavigationDrawerItemSelected(int position) {
if (!this.loaded){
return;
}
I also agree with using a boolean to check if onCreate() has finished loading. My only other suggestions is that for a quick fix you can use onSectionAttached(int number) to process each item selected instead of onNavigationDrawerItemSelected.