Android - Preventing duplicate window on Intent & StartActivity - android

I am trying to solve an issue with my android application.
The issue is that when i start a new instance or class by calling an Intent and StartActivity, a duplicate window or view opens.
I want to keep the same activity or view but execute/run a new class without affecting the view. The intent is simply to execute an extended class but i dont want it recreating or opening a duplicate view.
I have tried using android:Launchmode="singleTop" but to no effect.
I have used the standard android navigation drawer example xml and classes. You will see the content_main.xml contains a viewswitcher which includes 2 other xml files which doesn't need to load a new instance or activity...if that makes sense.
Im not sure if the issue lies with the BeaconTracking.java where it calls the super.onCreate(...) event again maybe causing the parent view to reopen??
Any ideas where i am going wrong?
Thanks in advance!
AndroidManifest.xml
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="#style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".BeaconTracking"
android:label="#string/app_name"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="#style/AppTheme">
</activity>
MainActivity.java
public class MainActivity extends AppCompatActivity implements ...
public ViewSwitcher switcher;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
...
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.nav_vehicle_tracking) {
Intent intent = new Intent(getApplicationContext(), BeaconTracking.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
} else if (id == R.id.nav_vehicle_info) {
//SWITCH TO BEACON SCREEN
switcher.setDisplayedChild(2);
}
//CLOSE NAVIGATION DRAWER WHEN BUTTON IS PRESSED
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
BeaconTracking.java
public class BeaconTracking extends MainActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
switcher.setDisplayedChild(1);
}
content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<ViewSwitcher
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/content_frame"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<include
android:layout_width="match_parent"
android:layout_height="match_parent"
layout="#layout/content_beacons" />
<include
android:layout_width="match_parent"
android:layout_height="match_parent"
layout="#layout/content_map" />
</ViewSwitcher>

android:Launchmode="singleTop" will not help here, why do you want to open another activity you can manage it in your current activity with view switcher, still you want to open another activity without duplicate window. In that case you can make the transparent ui of the opening activity.
<activity android:name = "BeaconTracking"
android:label = "#string/app_name"
android:theme = "#android:style/Theme.NoDisplay" >
or with theme #android:style/Theme.Translucent.NoTitleBar"
And replace the parent class to AppCompatActivity of BeaconTracking. But still BeaconTracking activity will be added in back stack.

Each Activity has its own views. If you don't want to open new views, you shouldn't start a new Activity. Just move the functionality of your BeaconActivity into the MainActivity.

Try using android:launchMode="singleInstance" in Manifest.

Related

Preventing my Activity to change orientation depending on its content

In my app MainActivity contains a BottomNavigation, so it can display different tabs. Now my intention was, to force some of them to stay in portrait orientation, regardless of how the user holds the device.
MainActivity.java:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation);
bottomNav.setOnNavigationItemSelectedListener(navListener);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new OverviewFragment()).commit();
}
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.nav_overview:
selectedFragment = new OverviewFragment();
break;
case R.id.nav_reports:
selectedFragment = new ReportsFragment();
break;
case R.id.nav_settings:
selectedFragment = new SettingsFragment();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, selectedFragment).commit();
return true;
}
};
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/bottom_navigation"/>
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="?android:attr/windowBackground"
app:menu="#menu/bottom_navigation"/>
At least one tab should be displayable in portrait AND in landscape mode. Do I have to add some stuff into the xml, or do some java magic? Thanks in advance!
You can set screenOrientation in AndroidManifest.xml.
<activity
android:name="yourActivity"
android:screenOrientation="portrait"/>
This activity will remain portrait always.
If you need it programatically then you can use this.
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Edit If i understood right, you want make different layout for different orientation.
Then create a layout-land directory and place the landscape layout XML
file in that directory.
To set Orientation, Just add screenOrientation inside your manifest in your activity tag
to set orientation - portrait
<activity
android:name=".YourActivityNAME"
android:theme="#style/AppTheme.NoActionBar"
android:screenOrientation="portrait"/>
to set orientation - landscape
<activity
android:name=".YourActivityNAME"
android:theme="#style/AppTheme.NoActionBar"
android:screenOrientation="landscape"/>
Or you can do this Programmatically by using code below:-
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Just Use this line with that activity you want to use in portrait mode in manifest.xml
android:screenOrientation="portrait"
like this
<activity
android:name=".app.comman.MainActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateAlwaysHidden" />
Add this line in your activity tag in Menifest file android:screenOrientation="portrait". like below,
<activity
android:name=".MainActivity"
android:screenOrientation="portrait"/>
Put these lines in Manifest so that the screen orientation would be portrait.
<activity
android:name=".MainActivity"
android:screenOrientation="portrait"
android:theme="#style/MyMaterialTheme" />

Navigation drawer in multiple activities

I know this question has been asked multiple times. But my concern is different.
Using Mr. Tamada Tutorial I've created a NavigaionActivity and multiple fragments to replace in FrameLayout. It's working fine.
Now, after selecting any option in a fragment, another activity gets open.
I want the same Navigation menu in that Activity.
Navigation view -- fragments -- Activity (display navigation view here)
What I tried:
use the xml code of displaying Navigation view in that activity.
(DrawerLayout, CoordinatorLayout, AppBarLayout etc)
Then in Activity.java, on click of menu item diverting to the Navigation Activity.
Code:
XML:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
....>
<android.support.design.widget.CoordinatorLayout
....>
<android.support.design.widget.AppBarLayout
....>
<android.support.v7.widget.Toolbar
.... />
</android.support.design.widget.AppBarLayout>
<LinearLayout
.... /> <!-- main content of this Acitivity-->
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
.... />
</android.support.v4.widget.DrawerLayout>
Activity.java:
public void dashboard(MenuItem item) {
Bundle bundle = new Bundle();
bundle.putString("fragment", Constant.DASHBOARD_FRAGMENT);
UtilityClass.newActivity(this, NavigationActivity.class, bundle);
}
And handling the call on Navigation Activity. It is doing the task but code isn't re-usable
Create a separate layout file for Navigation and include it in the Activity. But, this is replacing the main content. Here only included Navigation is visible.
Is there any other way to do it?
Downvoters - here the solution is..
Create an xml file which will have DrawerLayout and NavigationView (one can use the xml given in Question, without the main content) - navigation.xml
As suggested in many answers "create a BaseActivity which extends AppCompatActivity. And inflate navigation.xml.
public class BaseActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = View.inflate(this, R.layout.navigation, null);
// view declarations
DrawerLayout drawer = (DrawerLayout) view.findViewById(R.id.drawer_layout);
NavigationView navigationView = (NavigationView) view.findViewById(R.id.nav_view);
...... }}
In whichever Activity you wanna use this NavigationMenu, extend BaseActivity for that class.
GraphActivity extends BaseActivity { .... }
In GraphActivity.xml add the NavigationMenu code. You can't just include the navigation.xml it will disable the current xml widgets.
Done!
Try this:
public class MainActivity extends BaseActivity{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_describtion);
getLayoutInflater().inflate(R.layout.activity_main, frameLayout);
mDrawerList.setItemChecked(position, true);
}
Plz Don't use it this way
Instead use Google recommended MasterDetailFlow Design
You can read how to implement this on
https://inducesmile.com/android/android-fragment-masterdetail-flow-tutorial-in-android-studio/

Up Button in Toolbar doesn't do anything

I set up Toolbar in my app (for the first time) but the I can't set the Home (/Up) button to do anything when clicked.
I have 3 activitives (MainActivity , Second , Third) and I've defined the toolbar in all 3 but nothing happens when I click the Home button in each of the activitis I want the button to do his (in my understanding) default action which is go back to the Home Activity which is "MainActivity".
Here is some relevant code:
Toolbar layout (named: app_bar.xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/toolBar_background"
android:elevation="5dp"
android:title="#string/app_name" />
</RelativeLayout>
my 3 activities layout xmls:
Activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.example.noamm_000.finaltoolbarproject.MainActivity">
<include layout="#layout/app_bar"/>
//More layout code...
Activity_Second.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.noamm_000.finaltoolbarproject.Second">
<include layout="#layout/app_bar"/>
//More layout code...
Activity_Third.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.noamm_000.finaltoolbarproject.Third">
<include layout="#layout/app_bar"/>
//More layout code
Actually all the 3 activities simply include the toolbar layout which names "app_bar.xml".
Here is part of my Mainfest file where I configured the app_parent:
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".Second"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"/>
<intent-filter>
<action android:name="com.example.noamm_000.finaltoolbarproject.Second" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".Third"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"/>
<intent-filter>
<action android:name="com.example.noamm_000.finaltoolbarproject.Third" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
and ofcourse parts of my java code for each of my 3 activities:
MainActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar_id);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
mainBtn = (Button) findViewById(R.id.btn_main);
openSecondActivity();
}
public void openSecondActivity(){
mainBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent("com.example.noamm_000.finaltoolbarproject.Second");
startActivity(intent);
}
});
SecondActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
btnSecond = (Button) findViewById(R.id.btn_second);
toolbar = (Toolbar) findViewById(R.id.toolbar_id);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
openThirdActivity();
}
public void openThirdActivity(){
btnSecond.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent("com.example.noamm_000.finaltoolbarproject.Third");
startActivity(intent);
}
});
}
and ThirdActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
toolbar = (Toolbar) findViewById(R.id.toolbar_id);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
}
public boolean onCreateOptionsMenu(Menu menu){
getMenuInflater().inflate(R.menu.toolbar_menu,menu);
return super.onCreateOptionsMenu(menu);
}
You can see that all 3 Activities "onCreate" functions are pretty much the same..
When I start my app I can see the toolbar in all 3 activities and I can see the back arrow in all but clicking it do nothing.
I know I can set the toolbar.setNavigationOnClickListener but I just want it to make it default action which is go to home activity....
Thank you very much,
Noam
Try like this...
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == android.R.id.home) {
Intent i = new Intent(CurrentActivity.this, HomeActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
return true;
}
return super.onOptionsItemSelected(item);
}
Try this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
//finish(); or Do wahtever you wnat to do
return true;
}
return true;
}
If you are having parent activity,Follow this code,
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
if(NavUtils.getParentActivityIntent(this)== null) {
onBackPressed();
}else{
NavUtils.navigateUpFromSameTask(this);
}
break;
}
return super.onOptionsItemSelected(item);
}
Try this in your activities
#Override
public boolean onOptionsItemIdSelected(int id) {
switch (id) {
case R.id.home:
//do stuff
break;
}
return true;
}
In your case, I recommend to you create a AbstractActivity which inherit all your activities. So you can factor a number of behavior , including management of the toolbar button

Adding ActionBar with the arrow "GoBack" to PreferenceActivity?

I have a PreferenceActivity. I'm looking for a way to add ActionBar with the arrow "GoBack" to it. All the examples I found so far have been, to my mind, overcomplicated because if I had a simple Activity I could add ActionBar to it with one line of java code and that would be it.
I wonder, isn't there a simple way to add ActionBar with the arrow "GoBack" to PreferenceActivity?
UPDATE:
Here's my Preference activity:
public class PreferenceActivity123 extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MainPreferenceFragment()).commit();
}
public static class MainPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
}
// Add this in your androidmanifest.xml file
<activity
android:name=".SecondActivity"
android:label="#string/app_name"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
You have to set DisplayHomeasUpEnabled in your actionbar activity like
getSupportActionBar().setDisplayHomeAsUpEnabled(true);//Which will show back button
Define the parent activity in AndroidManifest.xml where the activity(PreferenceActivity) will be called once the back button in the action bar is pressed.
In your definition on the Manifest, add the line:
<activity
android:parentActivityName="com.example.activities.PreferenceActivity"
</activity>
or
Just listen the optionItemSelected method
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent intent = new Intent(this, PreferenceActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Edit :
In order to achieve same in Preference activity You need to make custom action bar style with back button in styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="PrefTheme" parent="#android:style/Theme.Holo.Light">
<item name="android:actionBarStyle">#style/PrefActionBar</item>
</style>
<style name="PrefActionBar" parent="#android:style/Widget.Holo.ActionBar">
<item name="android:displayOptions">showHome|homeAsUp|showTitle</item>
</style>
</resources>
Call the style in manifest like :
<application android:theme="#style/PrefTheme">
Call the action bar in activity
getActionBar().setDisplayHomeAsUpEnabled(true);
Just use android.support.v7.widget.Toolbar
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Toolbar actionbar = (Toolbar) findViewById(R.id.actionbar);
actionbar.setTitle("Settings");
actionbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_action_back));
actionbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
YourActivity.this.finish();
}
});
}
}
and your activity_settings.xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".SettingsActivity"
tools:menu="settings"
tools:actionBarNavMode="standard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/actionbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimaryDark"
/>
<FrameLayout
android:id="#id/content"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>

Keep the actionbar displayed in when changing PreferenceScreen

I'm trying to display a actionbar in my preference screen.
In order to do so I added the following code in my SettingActivity
public class PreferencesActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.preferences_activity);
getFragmentManager().beginTransaction()
.replace(R.id.container, new PreferencesFragment()).commit();
getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
then the rest of my code in PreferencesFragment.
This works fine, but as soon as I press on a PreferenceScreen preference, the actionbar is hidden. If I go back to the preference main screen I can see it again.
Any idea how to keep the actionbar displayed (and updated with the PreferenceScreen label) ?
Edit: Looking at the PreferenceScreen code it looks like a full screen Dialog is opened when the PreferenceScreen is clicked on. Because my preference has a title the Dialog should display a title as well... but it doesn't
// Set the title bar if title is available, else no title bar
final CharSequence title = getTitle();
Dialog dialog = mDialog = new Dialog(context, context.getThemeResId());
if (TextUtils.isEmpty(title)) {
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
} else {
dialog.setTitle(title);
}
I finally managed to find a way to do this.
It's kind of ugly but it works.
First I add an the same Intent to every PreferenceScreen definition in my preferences.xml file (make sure to update the value of the extra parameter)
<PreferenceScreen
android:key="pref1"
android:summary="Summary1"
android:title="Title1" >
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="my.package"
android:targetClass="my.package.activity.PreferencesActivity" >
<extra android:name="page" android:value="pref1" />
</intent>
...
</PreferenceScreen>
BTW my.package.activity.PreferencesActivity is my current Preference Activity
Then I add an intent-filter in the Manifest
<activity
android:name=".activity.PreferencesActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="#string/settings" >
<intent-filter android:label="Pref" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.PREFERENCE" />
</intent-filter>
</activity>
I add some code in the PreferenceActivity to handle this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.preferences_activity);
this.fragment = new PreferencesFragment();
this.fragment.setActivityIntent(getIntent());
getFragmentManager().beginTransaction()
.replace(R.id.container, this.fragment).commit();
}
Finally I add the following code in my PreferencesFragment class
public void setActivityIntent(final Intent activityIntent) {
if (activityIntent != null) {
if (Intent.ACTION_VIEW.equals(activityIntent.getAction())) {
if (intent.getExtras() != null) {
final String page = intent.getExtras().getString("page");
if (!TextUtils.isEmpty(page)) {
openPreferenceScreen(page);
}
}
}
}
private void openPreferenceScreen(final String screenName) {
final Preference pref = findPreference(screenName);
if (pref instanceof PreferenceScreen) {
final PreferenceScreen preferenceScreen = (PreferenceScreen) pref;
((PreferencesActivity) getActivity()).setTitle(preferenceScreen.getTitle());
setPreferenceScreen((PreferenceScreen) pref);
}
}
Had the same issue. Nested PreferenceScreens did not have an ActionBar. After stepping through the code, it appears to be caused by a conflict between AppCompatActivity and PreferenceScreen.
On one hand AppCompatActivity provides its own action bar, and therefore requires a theme descending from Theme.AppCompat which specifies windowNoTitle = true somewhere (could not pinpoint exactly where). On the other -- PreferenceScreen uses platform Dialog with the activity theme (rather than sub-theme, e.g., dialogTheme). Could be a bug.
If you don't care about Theme.AppCompat, here's a simple workaround that works on API 21+:
use android.preference.PreferenceActivity as the base class for your activity
create a theme for that activity:
<!-- This theme is used to show ActionBar on sub-PreferenceScreens -->
<style name="PreferenceTheme" parent="">
<item name="android:windowActionBar">true</item>
<item name="android:windowNoTitle">false</item>
</style>
specify android:theme="#style/PreferenceTheme" for this activity in the AndroidManifest.xml
What you'll get is more like a standard window title than a full ActionBar. I haven't yet figured out how to add a working back button, etc.
If you want to remain compatible with AppCompatActivity and the related themes, you'll need to request FEATURE_NO_TITLE on the activity window. Otherwise, you'll end up with two action bars (the built-in on top, and the support on bottom) in the top-level PreferenceScreen.
Since google sadly didn't fixed it until now, there is actually one much easier solution:
Set your SettingsActivity class to extend from just "Activity".
public class SettingsActivity extends Activity { ...
Create a new Theme in your v21/styles folder for your SettingsActivty and set the parent to "Theme.Material.*"
<style name="CustomThemeSettings" parent="android:Theme.Material">
<item name="android:colorPrimary">#color/...</item>
<item name="android:colorPrimaryDark">#color/...</item>
<item name="android:colorAccent">#color/...</item>
</style>
Set your new theme in your Manifest.xml file:
<activity
android:name=".SettingsActivity"
android:label="#string/title_activity_settingsactivity"
android:theme="#style/CustomThemeSettings" >
</activity>
It just works :)
(Optional) If you want to provide Material Design support for older Devices
you can put the SettingsActivity in an v21+ folder and create a other
SettingsActivity for older devices which has the parent AppCompat.
I have made an app that does have an action bar in the preferences activity. I can't seem to see the key to doing that, although I do remember it took me some time to nail it right.
It seems like our codes are quite similar. The only thing that gets to my attention is this import: import android.support.v7.app.ActionBarActivity;
Let me know if that helps any
public class SettingsActivity extends ActionBarActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new PrefsFragment() ).commit();
} // End of onCreate
static public class PrefsFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences); // Load the preferences from an XML resource
}
} // end of PrefsFragment
}
Addition: do you have this in your styles.xml?
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
</style>
but as soon as I press on a PreferenceScreen preference, the actionbar is hidden. If I go back to the preference main screen I can see it again.
I guess you are launching a new activity when clicked on the preference
Your Preference fragment should look like this
public static class PreferencesFragment extends PreferenceFragment {
public PlaceholderFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.your_preferences);
}
}
Then sample your_preferences as below
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent" >
<PreferenceCategory
android:title="#string/pref_category_title">
<PreferenceScreen
android:title="#string/title"
android:summary="#string/summary">
<intent
android:targetClass="com.your.package.Youractivity "
android:targetPackage="com.your.package"/>
</PreferenceScreen>
<PreferenceScreen
android:title="#string/another_title">
<intent
android:targetClass="com.your.package.activity2"
android:targetPackage="com.your.package.activity"/>
</PreferenceScreen>
</PreferenceCategory>
And finally the main thing Youractivity should extend from ActionBarActivity
public class Youractivity extends ActionBarActivity {
}
The above code works for me.
As you mentioned in the question the fullscreen Dialog might be a problem.
Try to change the Dialog style to:
<style name="Theme.Holo.Dialog">
or to style which has these properties:
<item name="windowActionBar">true</item>
<item name="windowNoTitle">false</item>
Here you can read how to get reference to the Dialog.
Note: Only for API>=14
Source1 and Source2
PreferenceActivity1.java
public class PreferenceActivity1 extends android.preference.PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref1);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
}
PreferenceActivity2.java
public class PreferenceActivity2 extends android.preference.PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref2);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
}
settings_toolbar.xml(layout)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:navigationContentDescription="#string/abc_action_bar_up_description"
android:background="?attr/colorPrimary"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="#string/app_name"
/>
pref1.xml(xml)
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="#android:style/Theme.Light" >
<PreferenceCategory android:title="Main Preferences" >
<CheckBoxPreference
android:key="wifi enabled"
android:title="WiFi" />
</PreferenceCategory>
<PreferenceScreen
android:key="key1"
android:summary=""
android:title="Wifi Settings" >
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.example.PreferenceActivity2"
android:targetPackage="com.example" />
</PreferenceScreen>
</PreferenceScreen>
pref2.xml(xml)
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="#android:style/Theme.Light" >
<PreferenceCategory android:title="Wifi Settings" >
<CheckBoxPreference
android:key="prefer wifi"
android:title="Prefer WiFi" />
</PreferenceCategory>
</PreferenceScreen>
Manifest
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name="com.example.PreferenceActivity1"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.PreferenceActivity2"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
Result
I created PreferenceCompatActivity that is an AndroidX-compatible drop-in replacement for the old PreferenceActivity.
It uses a compat fragment internally. Be sure to use the import only the androidx.preference.XXX classes instead of the android.preference.XXX ones.
public class PreferenceCompatActivity extends AppCompatActivity implements AppCompatCallback, PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
private PreferenceFragmentCompat fragment;
public void addPreferencesFromResource(#XmlRes int preferencesResId) {
fragment = new RootPreferencesFragment(preferencesResId);
getSupportFragmentManager().beginTransaction().replace(android.R.id.content, fragment).commitNow();
}
public PreferenceManager getPreferenceManager() {
return fragment.getPreferenceManager();
}
public PreferenceScreen getPreferenceScreen() {
return fragment.getPreferenceScreen();
}
public Preference findPreference(CharSequence key) {
return fragment.findPreference(key);
}
#Override
public boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref) {
LowerPreferencesFragment lowerFragment = new LowerPreferencesFragment(pref);
getSupportFragmentManager().beginTransaction().replace(android.R.id.content, lowerFragment).addToBackStack("lower").commit();
return true;
}
public static class RootPreferencesFragment extends PreferenceFragmentCompat {
private int preferencesResId;
public RootPreferencesFragment(int preferencesResId) {
this.preferencesResId = preferencesResId;
}
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(preferencesResId);
}
}
public static class LowerPreferencesFragment extends PreferenceFragmentCompat {
private PreferenceScreen prefs;
public LowerPreferencesFragment() {
}
public LowerPreferencesFragment(PreferenceScreen prefs) {
this.prefs = prefs;
}
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
if (prefs != null) {
setPreferenceScreen(prefs);
prefs = null;
}
}
}
}
Or see this gist.

Categories

Resources