My MainActivity calls an AsyncTask to do some network I/O. When the AsyncTask begins, I would like to 'light up' an icon in the ActionBar. When the AsyncTask completes, I would like to make that ActionBar icon invisible, i.e. upon AsyncTask completion, not via a button click.
At this point I can successfully light up the ActionBar icon upon AsyncTask start. At the completion of AsyncTask, I send another broadcast back to MainActivity to indicate that AsyncTask is completed. I need to be able to use this broadcast to make the ActionBar icon invisible. I am attempting to used InvalidateMenuOptions() to force onPrepareMenuOptions to recreate and make the ActionBar icon invisible, but it is not working. Here is my attempt so far - all code is excerpted from my MainActivity class
excerpt from MainActivity:
public class MainActivity extends Activity {
private static boolean dataXferRunning = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ActionBar actionBar = getActionBar();
actionBar.setHomeButtonEnabled(true);
// broadcast receiver to determine if BasestationTransfer is active
basestationBroadcastReceiver = new BasestationBroadcastReceiver();
basestationIntentFilter = new IntentFilter("XFER_RUNNING_ACTION");
boolean hasWifi = CWICUtil.getNetworkState(this);
if(hasWifi) {
if(dataXferRunning == false) {
containerCount = 0;
DBAdapter dbAdapter = CWICApplication.dbAdapter();
try {
containerCount = (int)dbAdapter.getUnsentContainersCount();
} catch (SQLException e) {
Log.e(TAG, "getUnsentContainersCount() failed: " + e.toString());
e.printStackTrace();
}
if(containerCount > 0) {
invalidateOptionsMenu();
startTransfer(); //AsyncTask
invalidateOptionsMenu();
}
}
}
}
}
my BroadcastReciever:
public static class BasestationBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
intent.getAction();
boolean isRunning = intent.getBooleanExtra("XFER_RUNNING", false);
if(isRunning) {
dataXferRunning = true;
} else {
dataXferRunning = false;
}
}
};
my onPrepareOptionsMenu:
#Override
public boolean onPrepareMenuOptions(Menu menu) {
if(dataXferRunning) {
menu.findItem(R.id.action_socketServiceConnected).setVisible(true);
} else {
menu.findItem(R.id.action_socketServiceConnected).setVisible(false);
}
return super.onPrepareOptionsMenu(menu);
}
So to summarize - I'm successfully receiving broadcasts from my AsyncTask with correct values. I have seen much code that does this with a buttonClick, however my issue is dynamically making my ActionBar icon invisible upon completion of AsyncTask. Also - this is my first time posting, let me know if I can clarify any issues plus thanks to this community because you have been getting me out of jams for months now.
In onCreateOptionsMenu(), you can hold on to a reference of your Menu object (via a class variable, or some other mechanism of your choice), like this:
Menu menu;
#Override
public boolean onCreateOptionsMenu( Menu menu ) {
getSupportMenuInflater().inflate( R.menu.my_menu, menu );
this.menu = menu;
return true;
}
Then, when you want to dynamically adjust the menu item's visibility, you can reuse that menu object reference to call menu.findItem(R.id.myId) to get your individual menu items and adjust their properties dynamically however you'd like.
Related
I programmed a Vocabulary Trainer with Vocabulary Cards. The Vocabulary Cards are Entries in a Room Database created from an asset. I am displaying these Vocabulary Cards with ViewPager2 in an Activity. I have a 'correct' and a 'false' button and when the user clicks on either, I want to update the Vocabulary Card (-> The entry in the sqlite database) and automatically swipe to the next item of the ViewPager2.
If I implement the buttons in the ViewPager2Adapter, I can't find a way to change the position of the ViewPager2. If I implement the buttons in the activity the sqlite entry does not update properly (After it updates the entry, the activity is constantly refreshed, it seems like it never the leaves the OnClick methode of the button).
So is it possible to change the position of ViewPager2 from inside the ViewPager2Adpater?
Thanks for your help!
That is the relevant code if I have the buttons in my ViewPager2Adapter. Here I don't know how to change the position of the ViewPager2
public void onBindViewHolder(#NonNull #NotNull ViewHolder holder, int position) {
VocabularyCard vocabularyCard = currentCards.get(position);
holder.btn_correct.setOnClickListener(view -> {
vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard);
});
holder.btn_false.setOnClickListener(v15 -> {
vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard);
});
That is the relevant code if I have the buttons in the Activity. Here the update function triggers an infinite updating of the Activity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initAll();
btn_correct_2.setOnClickListener(view -> {
int currentPos = viewpager2.getCurrentItem();
vocabularyViewModel.getCurrentCards().observe(this, vocabularyCards -> {
if (vocabularyCards.size() == currentPos){
Intent intent = new Intent(TestActivity.this, MainActivity.class);
startActivity(intent);
}else {
viewpager2.setCurrentItem(currentPos + 1);
}
VocabularyCard vocabularyCard = vocabularyCards.get(currentPos);
vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard);
});
});
btn_false_2.setOnClickListener(view -> {
int currentPos = viewpager2.getCurrentItem();
vocabularyViewModel.getCurrentCards().observe(this, vocabularyCards -> {
if (vocabularyCards.size() == currentPos){
Intent intent = new Intent(TestActivity.this, MainActivity.class);
startActivity(intent);
}else {
viewpager2.setCurrentItem(currentPos + 1);
}
VocabularyCard vocabularyCard = vocabularyCards.get(currentPos);
vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard);
});
});
Objects.requireNonNull(getSupportActionBar()).setTitle(getResources().getString(R.string.learn_new_words));
LiveData<List<VocabularyCard>> allNewCards = vocabularyViewModel.getAllNewCards(goal);
allNewCards.observe(this, vocabularyCards -> vocabularyViewModel.setCurrentCards(vocabularyCards));
vocabularyViewModel.getCurrentCards().observe(this, vocabularyCards -> {
viewPager2Adapter.setCurrentCards(vocabularyCards);
viewpager2.setAdapter(viewPager2Adapter);
viewpager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
}
#Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
}
});
});
The update function in the Room DAO is straightforward:
#Update
void updateSingleVocabularyCard(VocabularyCard vocabularyCard);
I left out all the code that is not relevant.
There are several ways to propagate an event from the adapter to the activity where you manage your cards using ViewPager2. Let's have a look how it can be done either using an interface or using the same view model. But in any case I strongly recommend you to update your database in a background thread to prevent any possible UI lags.
1. Using an interface
This option is more flexible since you can propagate events as well as pass data as parameters. You can also reuse this interface for other cases. As far as I See you have a holder that has 2 buttons for the users to make choices. So our event here would be something like ChoiceEventListener, let's call this interface like so. Then you'd have to add a method to handle this event from within anywhere you wanna hear this event, and let's call its handle method onChoice(). Finally we would need a variable to indicate what the choice is. Now that ready to implement, let's write the new interface...
ChoiceEventListener.java
public interface ChoiceEventListener {
void onChoice(VocabularyCard vocabularyCard, boolean choice);
}
The next thing to do is to implement this interface where you want to listen to this event. In this case it is in your activity. There are 2 ways to do this:
You make your activity to inherit its methods using the implements keyword
YourActivity.java
public class YourActivity extends AppCompatActivity implements ChoiceEventListener {
// Use a background thread for database operations
private Executor executor = Executors.newSingleThreadExecutor();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initAll();
// You must construct your adapter class with the listener
ViewPager2Adapter adapter = new ViewPager2Adapter(/* Other params... */, this);
}
#Override
public void onChoice(VocabularyCard vocabularyCard, boolean choice) {
if(choice) {
// User pressed the correct button
}
else {
// User pressed the false button
}
// Update card in the background
executor.execute(()-> vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard));
}
}
You can implement it as an anonymous function
YourActivity.java
public class YourActivity extends AppCompatActivity {
// Use a background thread for database operations
private Executor executor = Executors.newSingleThreadExecutor();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initAll();
// You must construct your adapter class with the listener
ViewPager2Adapter adapter = new ViewPager2Adapter(/* Other params... */, (vocabularyCard, choice) -> {
if(choice) {
// User pressed the correct button
}
else {
// User pressed the false button
}
// Update card in the background
executor.execute(()-> vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard));
});
}
}
Finally the ViewPager2Adapter class implementation would be something like this:
ViewPager2Adapter.java
public class ViewPager2Adapter extends RecyclerView.Adapter<ViewPager2ViewHolder> {
// Here is your listener to deliver the choice event to it
private final ChoiceEventListener listener;
// Constructor
public ViewPager2Adapter(/* Other params... */, ChoiceEventListener listener) {
/* Other inits */
this.listener = listener;
}
public void onBindViewHolder(#NonNull #NotNull ViewHolder holder, int position) {
VocabularyCard vocabularyCard = currentCards.get(position);
holder.btn_correct.setOnClickListener(view -> {
listener.onChoice(vocabularyCard, true); // true for correct
});
holder.btn_false.setOnClickListener(v15 -> {
listener.onChoice(vocabularyCard, false); // false for false :)
});
}
}
2. Use the ViewModel for inter-communication
In this option we use a LiveData object to make page switching. The only thing you need to know in your activity is the current position which you get it from the adapter class. Once you update it in the adapter, set the current position value in live data so that you can switch the page in your activity.
VocabularyViewModel.java
public class VocabularyViewModel extends ViewModel {
public MutableLiveData<Integer> mldCurrentPosition = new MutableLiveData<>(0);
}
YourActivity.java
public class YourActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initAll();
vocabularyViewModel.mldCurrentPosition().observe(this, currentPosition -> {
if(currenPosition == null) return; // ignore when null
viewpager2.setCurrentItem(currentPosition + 1);
}
}
}
Finally the ViewPager2Adapter class implementation would be something like this:
ViewPager2Adapter.java
public class ViewPager2Adapter extends RecyclerView.Adapter<ViewPager2ViewHolder> {
// Use a background thread for database operations
private Executor executor = Executors.newSingleThreadExecutor();
public void onBindViewHolder(#NonNull #NotNull ViewHolder holder, int position) {
VocabularyCard vocabularyCard = currentCards.get(position);
holder.btn_correct.setOnClickListener(view -> {
// Update card in the background
executor.execute(()-> vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard));
// Then invoke switching to the next card
vocabularyViewModel.mldCurrentPosition.setValue(position + 1);
});
holder.btn_false.setOnClickListener(v15 -> {
// Update card in the background
executor.execute(()-> vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard));
// Then invoke switching to the next card
vocabularyViewModel.mldCurrentPosition.setValue(position + 1);
});
}
}
I have a FrameLayout and put there some fragments by click on button, next click should remove fragment from FrameLayout, I do this by removeAllViews() (FrameLayout is in another Fragment so translaction method is in Activity).
I need to do some action when removeAllViews() starts and have to do it in Fragment class but something goes wrong.
I tried:
OnDestroy()
OnDestroyView()
OnPause()
in Fragment class
but it works like:
put Fragment in FrameLayout (from Activity)
use removeAllViews() (from Activity)
there is no Fragment in FrameLayout (is clear) but nothing else happens and methods are not working
put new Fragment in FrameLayout (from Activity) - now all methods (OnDestroy() from Fragment class) works (probably it's real time to destroy old fragment)
How is it possible to 'get moment' when Fragment is not exists for user? I want to send some information to server if user hides Fragment.
#Edit3
code from method from Activity where I want to make translaction
public void showProductsList(String productType,int containerID){
List<String> prodNames = new ArrayList<String>();
List<Long> prodIds = new ArrayList<Long>();
DatabaseDAOProdProtein dao = new DatabaseDAOProdProtein(getApplicationContext());
dao.open();
List<DatabaseProduct> productList = dao.getAllProducts();
for(int i=0;i<productList.size();i++){
prodNames.add(productList.get(i).getName());
prodIds.add(productList.get(i).getId());
}
dao.close();
ProductsList productsList = new ProductsList(productType,prodNames,prodIds);
productsList.setOnSystemUiVisibilityChangeListener
(new View.OnSystemUiVisibilityChangeListener() {
#Override
public void onSystemUiVisibilityChange(int visibility) {
// Note that system bars will only be "visible" if none of the
// LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
Toast.makeText(getApplicationContext(),"action1 " ,Toast.LENGTH_LONG).show();
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// TODO: The system bars are visible. Make any desired
// adjustments to your UI, such as showing the action bar or
// other navigational controls.
Toast.makeText(getApplicationContext(),"action2 " ,Toast.LENGTH_LONG).show();
} else {
// TODO: The system bars are NOT visible. Make any desired
// adjustments to your UI, such as hiding the action bar or
// other navigational controls.
Toast.makeText(getApplicationContext(),"action3 " ,Toast.LENGTH_LONG).show();
}
}
});
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(containerID, productsList).commit();
}
I used this method in another Fragment by:
((MainActivity) getContext()).showProductsList("carb", carbContainer.getId());
there is an error:
Error:(560, 21) error: cannot find symbol method setOnSystemUiVisibilityChangeListener(<anonymous OnSystemUiVisibilityChangeListener>)
You say:
"How is it possible to 'get moment' when Fragment is not exists for
user? I want to send some information to server if user hides
Fragment."
I now know you did not mean "hide", so just use the OnDestroy() method.
Try this to trigger the "hide"
View topLevelLayout = findViewById(R.id.top_layout);
topLevelLayout.setVisibility(View.INVISIBLE);
You cannot go into stopped state while Fragment (Activity) is visible. Android destroying activities, killing processes
The best way to make sure something runs via a view is to run it via a post:
topLevelLayout.post(new Runnable()
{
#Override
public void run()
{
topLevelLayout.removeAllViews();
}
}
To get notified of system UI visibility changes, register an View.OnSystemUiVisibilityChangeListener to your view (fragment).
https://developer.android.com/training/system-ui/visibility.html
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(getContext(),"action0 " ,Toast.LENGTH_LONG).show();
Fragment your_frag = new ProductsList(productType,prodNames,prodIds);
getSupportFragmentManager().beginTransaction().replace(containerID,your_frag).commit();
getSupportFragmentManager().executePendingTransactions();//make sure onCreateView has executed
your_frag.getRootView().setOnSystemUiVisibilityChangeListener
(new View.OnSystemUiVisibilityChangeListener() {
#Override
public void onSystemUiVisibilityChange(int visibility) {
// Note that system bars will only be "visible" if none of the
// LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
Toast.makeText(getContext(),"action1 " ,Toast.LENGTH_LONG).show();
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// TODO: The system bars are visible. Make any desired
// adjustments to your UI, such as showing the action bar or
// other navigational controls.
Toast.makeText(getContext(),"action2 " ,Toast.LENGTH_LONG).show();
} else {
// TODO: The system bars are NOT visible. Make any desired
// adjustments to your UI, such as hiding the action bar or
// other navigational controls.
Toast.makeText(getContext(),"action3 " ,Toast.LENGTH_LONG).show();
}
}
});
}
A typical fragment looks like this:
public class HomeFragment extends Fragment {
View mRootView = null;
public HomeFragment(){}//null constructor
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mRootView = inflater.inflate(R.layout.fragment_home, container, false);
return mRootView ;
}
public View getRootView ()
{
return mRootView;
}
}
What I'm trying to do is have a setting menu pull up when a button is pressed on my main menu (settings menu is implemented as a separate activity from my main). For simplicity's sake, assume that my main menu is blank except for 1 button that pulls up the settings menu. In the setting menu, there is one check box and one button "Done" that returns to the main activity.
How do I save a CheckBox's and load it (what should the code be, where should I put it, why, etc) ? I've tried googling it, and trying to replicate the results, but I can't seem to get it. 2 things have happened so far: nothing has saved, or my program crashes.
Once I have the information about the checkbox saved, how am I able to access this information from my main activity #I want to be able to run certain code based on if the user checked the box or not?
some results that I've landed on and tried:
How to save the checkbox state? - android
Saving Checkbox states
(Please keep in mind that I'm completely new to this)
public class Settings extends ActionBarActivity {
private static final String SETTING_CHECK_BOX = "SETTINGS";
private CheckBox cb;
//char boxChecked = '0';
#Override
protected void onCreate(Bundle savedSettings) {
super.onCreate(savedSettings);
cb = (CheckBox) findViewById(R.id.checkBox);
setContentView(R.layout.activity_settings);
cb.setChecked(isCheckedSettingEnabled());
}
private void setCheckedSettingEnabled(boolean enabled) {
PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(SETTING_CHECK_BOX, enabled).apply();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_settings, menu);
return true;
}
private boolean isCheckedSettingEnabled() {
return PreferenceManager.getDefaultSharedPreferences(this).getBoolean(SETTING_CHECK_BOX, false);
}
public void onPause() {
super.onPause();
// Persist the setting. Could also do this with an OnCheckedChangeListener.
setCheckedSettingEnabled(cb.isChecked());
}
public void clickedDone (View v) {
SharedPreferences settings = getSharedPreferences("SETTINGS", 0);
settings.edit().putBoolean("check",true).commit();
finish();
}
#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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
So now my app doesn't crash anymore, but the state is not remembered (always unchecked when settings menu is open). I changed cb.setChecked(checkState) to cb.setChecked(TRUE), which didn't change anything (still always unchecked when settings menu is open). What is going on?
onSaveInstanceState() is only for persisting data for that instance of the Activity. Once that Activity has had finish() invoked, that state is no longer relevant. You need to write your settings to persistent storage. A simple storage solution for your case is SharedPreferences.
public class Settings extends ActionBarActivity {
// Create a constant for the setting that you're saving
private static final String SETTING_CHECK_BOX = "checkbox_setting";
private CheckBox mCheckBox;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
mCheckBox = (CheckBox) findViewById(R.id.checkBox);
// Set the initial state of the check box based on saved value
mCheckBox.setChecked(isCheckedSettingEnabled());
}
#Override
public void onPause() {
super.onPause();
// Persist the setting. Could also do this with an OnCheckedChangeListener.
setCheckedSettingEnabled(mCheckBox.isChecked());
}
/**
* Returns true if the setting has been saved as enabled,
* false by default
*/
private boolean isCheckedSettingEnabled() {
return PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(SETTING_CHECK_BOX, false);
}
/**
* Persists the new state of the setting
*
* #param enabled the new state for the setting
*/
private void setCheckedSettingEnabled(boolean enabled) {
PreferenceManager.getDefaultSharedPreferences(this)
.edit()
.putBoolean(SETTING_CHECK_BOX, enabled)
.apply();
}
}
Once the state data is stored using onSaveInstanceState(), the system uses onRestoreInstanceState(Bundle savedInstanceState) to recreate the state.
If you are using onSaveInstanceState() You have to override the function onRestoreInstanceState() in the activity or use the saved state in onCreate(). I think it's better to use onRestoreInstanceState() , which can reduce the code in onCreate(), because the onSavedInstanceSate() is called only when the system
closes the app to make room for new applications to run. If you just want to save the checked state , use shared preference, no need of onSaveInstanceState().
//decalre in class
private CheckBox cb;
private SharedPreferences preferences ;
private SharedPreferences.Editor editor;
private boolean CHECKED_STATE;
#Override
protected void onCreate(Bundle savedSettings) {
super.onCreate(savedSettings);
setContentView(R.layout.activity_settings);
preferences = getApplicationContext().getSharedPreferences("PROJECT_NAME", android.content.Context.MODE_PRIVATE);
editor = preferences.edit();
CHECKED_STATE = preferences.getBoolean("check", false);
cb = (CheckBox) findViewById(R.id.checkBox);
cb.setChecked(CHECKED_STATE);
cb.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
editor.putBoolean("check", isChecked);
editor.commit();
}
});
}
this code saves the state on clicking the check box.
To make it save the state on Back Press , add the following to your activity.
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
editor.putBoolean("check", cb.isChecked());
editor.commit();
}
for more details on Save instance state please refer this link.
I'm rather new with Android, and with Java, for that matter, I apologize if the answer to my problem is a simple one.
The problem is that, once a certain Menu Item is selected, i need to run a rather long (2-3 seconds) task (involving HTTP requests, and as far as I know I need to execute said operation on a different thread than the main one) and then display part of the results gotten from the AsyncTask.
Everything works fine, except for the fact that the menu stays open the whole time the AsyncTask is being executed: I can't find a way of avoiding this.
I tried to sum up my problem with a shorter, but rather similar, example
Here's the MainActivity code:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(Menu.NONE,1,Menu.NONE,"Text");
return true;
}
#Override
public boolean onOptionsItemSelected (MenuItem mi) {
try {
String a = new AsyncTest ().execute().get();
Toast.makeText(MainActivity.this,a, Toast.LENGTH_SHORT).show();
return true;
}
catch (Exception e) {
return false;
}
}
}
And here's the AsyncTask
public class AsyncTest extends AsyncTask{
#Override
protected String doInBackground(Void... params) {
long i;
for (i=0;i<100000000;i++);
return "Lol";
}
}
I tried using closeOptionsMenu(); Right after onOptionsItemSelected, in order to close the Menu before the AsyncTask is executed, but it didn't work.
I didn't find much on the topic on google.
get() is blocking. so basically you are getting the work down on the other thread, but you are essentially waiting on the main UI thread preventing the menu from closing.
try this instead:
#Override
public boolean onOptionsItemSelected (MenuItem mi) {
new AsyncTest () {
public void onPostExecute(String result) {
Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
}
}.execute();
return true;
}
I can't figure out how I would go about implementing an up button in a PreferenceScreen. An up button displays a caret in your action bar next to your app icon that allows you to navigate the app's hierarchy, more info here.
I have a Preference Fragment that displays when my main activity is opened and I can get the up button to display by adding this line " getActionBar().setDisplayHomeAsUpEnabled(true);":
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(true);
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment())
.commit();
This causes the up button to display in the Preference Fragment, but I only want to show the up button when one of my PreferenceScreens is opened, allowing navigation to the main PreferenceFragment.
My app is analogous to the main settings app. Only the child screens, like Location Access, that opens from the main Settings app has the up arrow.
From this question, I simply added these two code blocks to my Preference Fragment:
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
super.onPreferenceTreeClick(preferenceScreen, preference);
// If the user has clicked on a preference screen, set up the action bar
if (preference instanceof PreferenceScreen) {
initializeActionBar((PreferenceScreen) preference);
}
return false;
}
And this one:
/** Sets up the action bar for an {#link PreferenceScreen} */
public static void initializeActionBar(PreferenceScreen preferenceScreen) {
final Dialog dialog = preferenceScreen.getDialog();
if (dialog != null) {
// Inialize the action bar
dialog.getActionBar().setDisplayHomeAsUpEnabled(true);
// Apply custom home button area click listener to close the PreferenceScreen because PreferenceScreens are dialogs which swallow
// events instead of passing to the activity
// Related Issue: https://code.google.com/p/android/issues/detail?id=4611
View homeBtn = dialog.findViewById(android.R.id.home);
if (homeBtn != null) {
OnClickListener dismissDialogClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
};
// Prepare yourselves for some hacky programming
ViewParent homeBtnContainer = homeBtn.getParent();
// The home button is an ImageView inside a FrameLayout
if (homeBtnContainer instanceof FrameLayout) {
ViewGroup containerParent = (ViewGroup) homeBtnContainer.getParent();
if (containerParent instanceof LinearLayout) {
// This view also contains the title text, set the whole view as clickable
((LinearLayout) containerParent).setOnClickListener(dismissDialogClickListener);
} else {
// Just set it on the home button
((FrameLayout) homeBtnContainer).setOnClickListener(dismissDialogClickListener);
}
} else {
// The 'If all else fails' default case
homeBtn.setOnClickListener(dismissDialogClickListener);
}
}
}
}
If your complete application is a preferences screen, then you can make your main activity a PreferenceActivity and the sub-levels can be fragments. This way the 'up' functionality is going to be by default what you are looking for.
Have a look at this.
For the XML:
<Preference android:title="Acts like a button"
android:key="button"
android:summary="This will act like a button"/>
Then for the Java in your onCreate()
Preference button = (Preference)findPreference("button");
button.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
//code for what you want it to do
return true;
}
});