ActionBarSherlock, GoogleMap, and GPS ?[SOLVED- with the quickness] - Java for Android App Development

Ok so here's a weird one for you guys.
I have a map, with ABS. I don't want the gps to come up by itself, I'm making it a user choice.
I dont set up MylocationLayer until the user selects it. for some reason, It isn't happening from the action bar.
right now the user has to long press on the map to turn GPS on, like this,
Code:
googleMap.setOnMapLongClickListener(new OnMapLongClickListener() {
[user=439709]@override[/user]
public void onMapLongClick(LatLng point) {
//turns on GPS and adds the famous location button
googleMap.setMyLocationEnabled(true);
}
I can interact with the map with other things fine from the action bar.
Notably, switching map types(satellie, and regular mode)
and can clear markers on my map like this
Code:
else if (item.getTitle().toString().equalsIgnoreCase("Clear The Map")) {
// Removing the marker and circle from the Google Map
googleMap.clear();
googlemap.SetMyLocationEnabled(false) also does not work to clear the gps from the ABS.
anyone have any idea why gps isn't able to be toggled from the ABS, or am I just losing it?:laugh:

Could you please post your on onOptionsItemSelected() method?
Did you change the imports posted here? http://actionbarsherlock.com/usage.html
com.actionbarsherlock.app.ActionBar
com.actionbarsherlock.view.Menu
com.actionbarsherlock.view.MenuItem
com.actionbarsherlock.view.MenuInflater
Click to expand...
Click to collapse

Bleh, got it working. for some reason eclipse didn't take my references to the map when i originally tried it, and i dumped that and was trying without the reference for awhile. but then i put the reference back it now it works. go figure.
And i inflate the ABS differently. I do like this
Code:
//cuz maps are now fragments
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SubMenu;
then in the code like this
Code:
//in oncreate
setHasOptionsMenu(true);
//later
[user=439709]@override[/user]
public boolean onCreateOptionsMenu(Menu menu) {
//what shows in the actionsbar
SubMenu subMenu = menu.addSubMenu("Map Type");
//what pops up when I click the Submenu option
subMenu.add("Street Map");
subMenu.add("Satellite");
subMenu.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
SubMenu subMenu1 = menu.addSubMenu("Settings");
subMenu1.add("Clear The Map");
subMenu1.add("Turn on GPS");
subMenu1.add("Other stuff");
subMenu1.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
return true;
that works on various gingerbreads (2.3.5 and 2.3.6) and Nexus 7 tablet(4.2)
code for options selected in case anybody wants to put it in their apps
Code:
[user=439709]@override[/user]
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getTitle().toString().equalsIgnoreCase("Street Map")) {
//This findfragmentbyID is the reference I was talking about
GoogleMap googleMap = ((SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map)).getMap();
if (googleMap != null)
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
else
Toast.makeText(this, "Street Map", Toast.LENGTH_LONG)
.show();
}
else if (item.getTitle().toString().equalsIgnoreCase("Turn on GPS")) {
//the reference that it needed,but didnt work at first
GoogleMap googleMap = ((SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map)).getMap();
//pops up the button and GPS
googleMap.setMyLocationEnabled(true);
//you can also set that to false, if you want to turn off the gps
}
the weird thing is, to clear the map, I don't need to give a reference to the map, it just does it no problem.

out of ideas said:
Bleh, got it working.
Click to expand...
Click to collapse
Great.

Related

Help writing something with setOnItemClickListener

In my Android app, I have a sound that I want to play when a certain selection has been made from a spinner, but I want it to play the when the user actually makes the proper selection (or just after). My problem is that although the sound does play when they make the correct selection, as long as that selection stays chosen, it also plays every time the app starts up, when it should ONLY play at the time it's chosen. I think I need to change my setOnItemSelectedListener to setOnItemClickListener, but I'm not sure how (still pretty new to java). Can any generous soul out there show me how to change this up (assuming that's how to best solve this problem)?
Here is the code I have now:
Code:
fitnessSpinner = (Spinner) findViewById(R.id.fitness_spinner);
ArrayAdapter adapter4 = ArrayAdapter.createFromResource(
this, R.array.fitness_array, android.R.layout.simple_spinner_item);
adapter4.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
fitnessSpinner.setAdapter(adapter4);
fitnessSpinner.setOnItemSelectedListener(new OnItemSelectedListener()
{
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long i) {
Log.d("test", "p: " + position + " " + i);
if(position == 0) {
//First Entry
MediaPlayer mp = MediaPlayer.create(mContext, R.raw.bowchica);
mp.start();
} if(position == 4) {
MediaPlayer mp = MediaPlayer.create(mContext, R.raw.debbie2);
mp.start();
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
I haven't try the below code but you can try it on your own and tell us.
In onCreate() declare MediaPlayer mp;
In every if statement that you use for check insert this code:
Code:
if(mp!=null){mp.release();}
int resid = R.raw.yoursound;
mp = MediaPlayer.create(this, resid);
After that override the methods onPause() and onResume() and insert this:
if(mp!=null){mp.release();}
If it is still playing a sound when you start your app, then you should check your code again if you have set as default option any of your selection options.
I would LOVE to try this out...Unfortunately, I'm way too dumb at this point point ot figure out exactly where those code snippets would go inside of what I already have.
Does anyone have a couple of minutes to show me where it would go?
Below is a sample code. Since i don't know your code I give you a snippet that you should adjust it to your code.
Code:
public class SampleSound extends Activity{
private Spinner fitnessSpinner;
private MediaPlayer mp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);//here goes your layout
setViews();//here you will set all your views(spinners buttons textviews etc..)
setAdapters();//set your adapters here
setListeners();//
}
private void setListeners() {
fitnessSpinner.setOnItemSelectedListener(new OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long i) {
Log.d("test", "p: " + position + " " + i);
if(position == 0) {
//First Entry
if(mp!=null){mp.release();}
int resid = R.raw.bowchica;
mp = MediaPlayer.create(this, resid);
mp.start();
} if(position == 4) {
if(mp!=null){mp.release();}
int resid = R.raw.debbie2;
mp = MediaPlayer.create(this, resid);
mp.start();
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
}
private void setAdapters() {
ArrayAdapter adapter4 = ArrayAdapter.createFromResource(this, R.array.fitness_array, android.R.layout.simple_spinner_item);
adapter4.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
fitnessSpinner.setAdapter(adapter4);
}
private void setViews() {
fitnessSpinner = (Spinner) findViewById(R.id.fitness_spinner);
}
public void onResume(){
super.onResume();
if(mp!=null){mp.release();}
}
public void onPause(){
super.onPause();
if(mp!=null){mp.release();}
}
}
I really appreciate the help. I put the code in my routine, but it still plays the sound every time the activity is loaded (as long as the selection in the spinner is correct). It should only play the sound when the correct selection is made.
Any other ideas?
I am sure that your Spinner is set to some value (since you have values to display). Because your Spinner points to a selection (doesn't matter if you have selected or it is selected by default) your sound plays (even when you start the app).
A way to stop the sound playing at start is to declare and an other Item like you did with the previous 4 and set it as default selection of your Spinner.
To sum up:
1.You have to append in R.array.fitness_array an Item (like you did with the previous Items) and give it a name.
2.At the end of method setAdapters() insert this:
Code:
fitnessSpiner.setSelection(5);// or whatever is your selection number
Now it should work but you should know that this is not a good practice and you should try make a ListView or something else.
I'd be happy to change this out to a listview, or whatever would work. I just have to give my user a choice of 4 or 5 items, from which they can choose only one. Something like a drop down box, but in Android, I thought my only option was a spinner. But whatever I use, I have to be able to play a sound when certain items are chosen, but ONLY when those items are chosen, NOT whenever the activity is called up.
Any specific ideas of what I might change to?
What if I had another control like a textview or an edittext (with it's visibility property set to false) that I programatically populated with the users selection (when it's the selection that I want) and then have an OnItemClcickListener set to play the sound?
Could that work?
I will answer from the last to the top of your questions.
1.You can do whatever you want with android. You want TextViews and EditTexts with complex and nested Layouts you can do it. Write services that will communicate with your contacts through a content provider? You can do it.
Write, read and test code. Only this way you will actually learn.
2.Read developer.android.com. Read the android tutorials from there and specifically the Notepad example. You will learn a lot.
A good resource with small examples for ListViews is this.
3.Have you tried the changes I told you from the last post? Did it worked?
Since you just started with android and programming you must first be happy if you have the expected result and then read more to make your code better
Your suggested changes (fitnessSpiner.setSelection(5);// or whatever is your selection number) would stop the sound from playing, but defeat the apps purpose. Every time this activity is loaded, the spinners hit preferences to load the previously stored data. So if I force the spinner to a different selection to NOT play sound when the activity loads, then I would be displaying the wrong data for the user.
Yes you are right. So it is better to make a ListActivity. Read developer.android.com and the link i gave you before. You will be ok with this!
You're using "setOnItemSelectedListener", which sounds like when the app starts, its getting "selected" again.
Have you tried using "setOnItemClickListener" instead?
fitnessSpinner.setOnItemClickListener(new AdapterView.OnItemClickListener () {
public void onItemClicked() {}
};
Lakers16 said:
You're using "setOnItemSelectedListener", which sounds like when the app starts, its getting "selected" again.
Have you tried using "setOnItemClickListener" instead?
fitnessSpinner.setOnItemClickListener(new AdapterView.OnItemClickListener () {
public void onItemClicked() {}
};
Click to expand...
Click to collapse
onClickListener doesn't work for the spinner...I wish it did.
I REALLY need the drop down functionality of teh spinner, so I guess I'm going to try and figure out a way to have an invisible edittext that I set to the spinner selection and then use onClickListener or onChange...

[Q] Using Split Action in android

Hi!
My self Raj, i have a problem when using the split action in my application.
i am doing an E-Menu for an restaurant. i list out all available category in major listview if the user click on the item of major list it should display all available minor items of its in behind of the Major listview.
I found one solution in Google it is possible by using split action.
Can anyone guide me / give some sample i may know about it..,
I am waiting for your guide.,
Have A Happy Day..,
Thanks to all..,
Simply add the following line to your <activity> or <application> tag in your AndroidManifest :
Code:
uiOptions="splitActionBarWhenNarrow"
EDIT : As a side note, it seems you want the split actionbar to be displayed only after the user clicked something, in that use case, the Contextual ActionBar seems more suited.
To use it, simply define your actionbar items in a menu.xml just like the normal actionbar, then in your java code use something like :
Code:
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item1:
//do something
mode.finish();
return true;
case R.id.menu_item2:
// do something else
mode.finish();
return true;
case R.id.menu_item3:
// etc....
mode.finish();
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
And in the onClickListener() of the component that triggers the contextual ActionBar, call it like that :
Code:
if (mActionMode != null)
// Do nothing
else
mActionMode = startActionMode(mActionModeCallback);
You might want to use the ActionBarSherlock Library in order to keep compatibility with gingerbread/froyo

[Q]Content Provider - Huge Data

Hi,
Im using a content provider to query data, the following code was working good until I test it in another device(low end) with a larger data(~3000). With a larger data app became unusable, what can I do for improve this?
Code:
public void ContentSearch(String uriS,String id)
{
Uri uri = Uri.parse(uriS);
Cursor cur = getContentResolver().query(uri, NULL,
"_id = " + id, null, null);
cur.moveToFirst();
do {
//Do Things
} while (cur.moveToNext());
cur.close();
}
try to put it in a thread:
Code:
new Thread(new Runnable() {
[user=439709]@override[/user]
public void run() {
//CODE GOES HERE
}
}).start();
You do this for anything that might take the system a long time to execute and isn't directly needed for the UI.
If it is needed by the UI try an AsyncTask:
Code:
AsyncTask<Params,Progress,Result>() {
[user=439709]@override[/user]
protected Result doInBackground(Params params) {
}
protected void onProgressUpdate(Progress progress) {
}
protected void onPostExecute(Result result) {
}
}.execute();
I never used Content Providers so I'm not sure what you would put in for each thing on the Async but here is the Android Docs perhaps you can figure it out
Im filling an array to inflate in listview, my approach is load 25 items then break, and when the list reaches the end load more 25 and so on, but it seems that the cursor is in the same overloaded.
I need it for the UI so I dont have sure if the thread solve the problem, but I will try it anyway.
avlisF said:
Im filling an array to inflate in listview, my approach is load 25 items then break, and when the list reaches the end load more 25 and so on, but it seems that the cursor is in the same overloaded.
I need it for the UI so I dont have sure if the thread solve the problem, but I will try it anyway.
Click to expand...
Click to collapse
You fill the array then you fill the list? This might be what's causing our crash as the list is trying to setup before the array is done.
You could just use the async to do the lookup and set the list item info in the list adapter and as the async finishes each lookup it will enter each item in the list
Sent from my Nexus 7 using XDA Premium HD app

Android/Java Newbie

Hi all, im having a go at developing a simple app. i have little experience with Java and Android development. i have a little test app at the moment and have created a new class, im trying to create a new instance of this class on a button click. it fails to do so, i cant for the life of me see why so.. can someone shed any light on this?
Thanks
Debuging this shows it hitting the "LocationFactory locationf = new LocationFactory();" line and throwing an exception-
"java.lang.NullPointerException"
Main
Code:
package com.example.testapp;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
import java.io.IOException;
public class MainActivity extends Activity {
private static final Context Context = null;
protected static final String TAG = null;
[user=439709]@override[/user]
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
[user=439709]@override[/user]
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void mainButton(View view) throws IOException {
try {
LocationFactory locationf = new LocationFactory();
Toast.makeText(this, locationf.getAddress(),Toast.LENGTH_LONG).show();
} catch (Exception e)
{
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
}
}
}
Class
Code:
package com.example.testapp;
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import java.io.IOException;
import java.util.Locale;
import java.util.List;
public class LocationFactory
{
private static final Context Context = null;
Geocoder geocoder = new Geocoder(Context, Locale.getDefault());
LocationManager manager = (LocationManager) Context.getSystemService(android.content.Context.LOCATION_SERVICE);
public double Latitude = 0.0;
public double Longitude = 0.0;
public LocationFactory()
{
}
public String getAddress() throws IOException
{
String ReturnAddress = "";
String Address = "", City = "", Country = "";
List<Address> addresses = null;
if(manager.isProviderEnabled(LocationManager.GPS_PROVIDER))
{
// Use GPS Radio Location
Location GPSlocation = manager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
Latitude = GPSlocation.getLatitude();
Longitude = GPSlocation.getLongitude();
}
else
{
// Use Cell Tower Location
Location NETlocation = manager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Latitude = NETlocation.getLatitude();
Longitude = NETlocation.getLongitude();
}
if(Latitude > 0 && Longitude > 0)
{
addresses = geocoder.getFromLocation(Latitude, Longitude, 1);
if(!addresses.isEmpty())
{
Address = addresses.get(0).getAddressLine(0);
City = addresses.get(0).getAddressLine(1);
Country = addresses.get(0).getAddressLine(2);
}
}
ReturnAddress = Address + " " + City + " " + Country;
return ReturnAddress;
}
}
I don't see anywhere in your code where you are calling the mainButton(View view) method. In the Android lifecycle, the onCreate method is the equivalent of a normal Java program's main() method, which means that code execution begins with the first line of onCreate(). Not knowing what you're trying to do, a good start would be to call your mainButton() method AFTER setContentView() in onCreate().
Side note: your mainButton() method has a View parameter that is never used. Is there a reason for that?
Android activity lifecycle: http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
You have to use an intent on that button click, use the method onClickListener and define the intent in the androidmanifest.xml
e.g
Code:
Button button = (Button) findViewById(R.id.[B]button[/B]) // replace latter button with actual id defined in main xml.
button.setOnClickListener(new View.OnClickListener() {
[user=439709]@override[/user]
public void onClick(View arg0) {
// TODO Auto-generated method stub
startActivity(new Intent("[B]com.example.packagename.CLASSNAME[/B]")); // this should be your own package name.
}
});
Also define this in android manifest under the <application> and </application>
Code:
<activity
android:name=".[B]CLASSNAME[/B]"
android:label="@string/app_name"
>
<intent-filter>
<action android:name="[B]com.example.packagename.CLASSNAME[/B]" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Change the values of BOLD text according to your own values.
I tried to help you as far as I understood your question. Please let me know if you face any problem I would be more than happy to help you. Rest I am also in the learning phase so you can always PM me if you face any problem.
Hit thanks if I have helped you in any way.
coolbud012 said:
You have to use an intent on that button click, use the method onClickListener and define the intent in the androidmanifest.xml
Click to expand...
Click to collapse
Nope! He didn't say that he wanted to launch a new Activity when the button is clicked. He wants to create a new instance of his LocationFactory Class.
jpepin said:
Nope! He didn't say that he wanted to launch a new Activity when the button is clicked. He wants to create a new instance of his LocationFactory Class.
Click to expand...
Click to collapse
Oops yeah right read that now...I thought he want to start an activity... Anyways tried to delete my reply but not getting an option to delete.
There are many flaws in his code. And the other thing is if its his first app and if he has low level of programming experience then according to me it would be a next to impossible app for him, as per his code and what he is trying to implement.
I think he should rather start up with small apps, understand things and then move on to complex apps.
P.S - its just my opinion
Click to expand...
Click to collapse
Agreed that he should start small...which is exactly why your suggestion for creating and handling Intents makes no sense. Before that, he should first understand the activity lifecycle. Until then, he can just stick to trivial single-activity apps to gain experience.
OP: This code should be placed in the onCreate method:
Code:
Button button = (Button) findViewById(R.id.your_button_ID_here)
button.setOnClickListener(new View.OnClickListener() {
[user=439709]@override[/user]
public void onClick(View arg0) {
mainButton(); // get rid of the View parameter in this method...it's not needed
}
});
This will cause a new instance of your LocationFactory to be created, and will also cause your Toast message to be displayed.
thanks for the replies. yes you are right in that i am inexperienced, but this is just a test app for me to play around with and learn on. i tend to learn better by doing rather than constantly reading. thanks for your suggestions ill look into them
osmorgan said:
thanks for the replies. yes you are right in that i am inexperienced, but this is just a test app for me to play around with and learn on. i tend to learn better by doing rather than constantly reading. thanks for your suggestions ill look into them
Click to expand...
Click to collapse
I also believe in the same, I also keep on doing experiments and testing things out.
What I would suggest is that start with a small app and understand the insights on how android works and all...
Thanks
Potential Solution
Alright, I think I've found your problem. Have a look at where you define your variables in your LocationManager class:
Code:
private static final Context Context = null;
Geocoder geocoder = new Geocoder(Context, Locale.getDefault());
LocationManager manager = (LocationManager) Context.getSystemService(android.content.Context.LOCATION_SERVICE);
This is your problem:
Code:
Context Context = null;
If your context is null, and you use it to create a geocoder and call Context.getSystemService, you'll hit a null pointer. You're trying to access an object (the Context) that doesn't even exist
I'd recommend you pass the context in the LocationManager constructor and then instantiate your objects there. That's standard java procedure.
Code:
private Context mContext = null;
Geocoder geocoder = null;
LocationManager manager = null;
public double Latitude = 0.0;
public double Longitude = 0.0;
public LocationFactory(Context context)
{
this.mContext = context;
this.geocoder = new Geocoder(context, Locale.getDefault());
this.manager = (LocationManager) Context.getSystemService(android.content.Context.LOCATION_SERVICE);
}
I also renamed Context to mContext - it's generally a good idea to keep the instance's name separate from the class name.
Try that - it should work. Please feel free to ask any more questions - this is how I learned, and I think it's the best way!

Action Bar and OptionsMenu troubleshooting

I just discovered how to use the action bar to have a OptionsMenu. I just solved a problem with it and I wanted to know if I did it the right way.
What I did
So, I added the menu to a fragment started by an activity, adding to it the setHasOptionsMenu(true) in the onCreate method and setting up the two convenience methods public void onCreateOptionsMenu() and public boolean onOptionsItemSelected() of course setting up the xml first.
The problem
Now, if I rotate my device in landscape mode the button in the action bar duplicates. If I put it in portrait mode again, the number of items stays the same (I'm sure it doesn't actually increase, checked the size in different ways) though.
What I thought and how I solved it
So, I was thinking about some fragment overlaps, but if they actually overlap then I shouldn't notice anything, right?
Is the menu being recreated, while not destroyed when the fragment is destroyed?
I solved the problem removing the item in the menu, in the Fragment.onDestroy() method manually.
Is the menu supposed to be cleared manually, or there is something wrong with my code (eg. fragments overlapping, etc..) ?
domenicop said:
Is the menu supposed to be cleared manually, or there is something wrong with my code (eg. fragments overlapping, etc..) ?
Click to expand...
Click to collapse
Could you please post your code? That would make helping much easier.
nikwen said:
Could you please post your code? That would make helping much easier.
Click to expand...
Click to collapse
Of course. Thanks for the interest.
This is the onCreate method of MainActivity.java, from where I handle the arrangement of fragments on the screen.
Also, place check my comment under the line "Log.d(TAG, "Orientation Portrait detected.");", where I try to explain why I handle fragments in that specific way. It's the way I understood it, but I'm not sure if that's correct.
Code:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Initialize the mDatabase
mContactsDatabase = ContactsDatabase.getInstance(getApplicationContext());
// Determine device orientation
mDualPane = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
// Set the fragment that will be changed
mFragmentToReplace = mDualPane ? R.id.contactsPagerFragmentContainer : R.id.portraitFragmentContainer;
// Set up the GUI
FragmentManager fm = getSupportFragmentManager();
if (!mDualPane) {
Log.d(TAG, "Orientation Portrait detected.");
// First, look for previously saved fragments
// findByFragmentId(int id) look for the fragment that was previously associated
// to the resource that has for id the argument passed in. Then, we try to cast it
// to the type of fragment we want, and if that goes all right, we have our fragment.
// Else, null will be returned.
mContactListFragment = (ContactListFragment) fm.findFragmentById(R.id.portraitFragmentContainer);
if (mContactListFragment == null) {
mContactListFragment = ContactListFragment.newInstance(mContactsDatabase);
fm.beginTransaction()
.replace(R.id.portraitFragmentContainer, mContactListFragment)
.commit();
}
}
else {
Log.d(TAG, "Orientation Landscape detected.");
// First, look for previously saved fragments
mContactListFragment = (ContactListFragment) fm.findFragmentById(R.id.landscapeFragmentContainer);
mContactsPagerFragment = (ContactsPagerFragment) fm.findFragmentById(R.id.contactsPagerFragmentContainer);
if (mContactListFragment == null) {
mContactListFragment = ContactListFragment.newInstance(mContactsDatabase);
fm.beginTransaction()
.replace(R.id.contactListFragmentContainer, mContactListFragment)
.commit();
}
if (mContactsPagerFragment == null) {
final int FIRST_CONTACT_POSITION = 0;
mContactListFragment = ContactListFragment.newInstance(mContactsDatabase);
mContactsPagerFragment =
ContactsPagerFragment.newInstance(FIRST_CONTACT_POSITION, mContactsDatabase);
fm.beginTransaction()
.replace(R.id.contactsPagerFragmentContainer, mContactsPagerFragment)
.commit();
}
}
}
This are the relevant pieces of the ContactListFragment.java, that have something to do with the menu
Note that I changed the way I checked for double menu entries.
Now I check if (menu.size() != 1), because I have just one item in there.
If I remove that clause, there will be two item in the menu after rotating to landscape mode, and if I take the device back to portrait mode, the two items will remain two. That's so even if I change from landscape to portrait and vice versa a hundred times from now, the menu items will always be two.
Code:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
Bundle args = getArguments();
mDatabase = (ContactsDatabase) args.getSerializable(DATABASE);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
if (menu.size() != 1) {
inflater.inflate(R.menu.contact_list_fragment_menu, menu);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.addContactMenu:
mCallback.onAddContactMenuOptionSelected();
default:
return super.onOptionsItemSelected(item);
}
}
domenicop said:
I just discovered how to use the action bar to have a OptionsMenu. I just solved a problem with it and I wanted to know if I did it the right way.
What I did
So, I added the menu to a fragment started by an activity, adding to it the setHasOptionsMenu(true) in the onCreate method and setting up the two convenience methods public void onCreateOptionsMenu() and public boolean onOptionsItemSelected() of course setting up the xml first.
The problem
Now, if I rotate my device in landscape mode the button in the action bar duplicates. If I put it in portrait mode again, the number of items stays the same (I'm sure it doesn't actually increase, checked the size in different ways) though.
What I thought and how I solved it
So, I was thinking about some fragment overlaps, but if they actually overlap then I shouldn't notice anything, right?
Is the menu being recreated, while not destroyed when the fragment is destroyed?
I solved the problem removing the item in the menu, in the Fragment.onDestroy() method manually.
Is the menu supposed to be cleared manually, or there is something wrong with my code (eg. fragments overlapping, etc..) ?
Click to expand...
Click to collapse
I agree with nikwen but broadly the idea is...
- the menu belongs to the Activity not the Fragment.
- for an Activity for which you'd like an options menu you override onCreateOptionsMenu and do 2 things...
1/ call menu.add(...) for each menu item
2/ return 'true' at the end, so that your menu can be displayed
Also, see the Activity docs for onCreateOptionsMenu()
"This is only called once, the first time the options menu is displayed.
To update the menu every time it is displayed, see onPrepareOptionsMenu(Menu)."
If you want to add menu options to the Activity menu from within a Fragment you can also..
- override setHasOptionsMenu() in Fragment to return true
- override onCreateOptionsMenu() to add any items you like (just like you did at the Activity level)
- override onDestroyOptionsMenu()
The key thing here is that onCreateOptionsMenu() in Fragment is adding to the Activity menu.
It's hard to see without debugging exactly what's going on here but watch for calls to all of the above methods in Activity and Fragment and that will probably tell you what's going on.
If it is possible to control all menu options at the Activity level instead of the Fragment level, I would do that.
If not, and you need to use the Fragment menu methods, beware of Android's Fragment management (saving / restoring state)
Also, make sure your Fragments have an ID and/or tag.
(from the docs..)
"The fragment being instantiated must have some kind of unique identifier so that it can be re-associated with a previous instance if the parent activity needs to be destroyed and recreated. This can be provided these ways:
If nothing is explicitly supplied, the view ID of the container will be used.
android:tag can be used in <fragment> to provide a specific tag name for the fragment.
android:id can be used in <fragment> to provide a specific identifier for the fragment."
Finally, if all else fails, using Menu's findItem() before calling add() would be a safeguard, I suppose.
---------- Post added at 10:14 PM ---------- Previous post was at 09:52 PM ----------
domenicop said:
Of course. Thanks for the interest.
Click to expand...
Click to collapse
Sorry caught in the crossfire - have only just seen your code.
I think much of the above applies.
Set the menu up in the Activity instead of the Fragment, if you can.
I would also consider using layout-port and layout-land to control your two different layouts.
PicomatStudios said:
I agree with nikwen but broadly the idea is...
- the menu belongs to the Activity not the Fragment.
- for an Activity for which you'd like an options menu you override onCreateOptionsMenu and do 2 things...
1/ call menu.add(...) for each menu item
2/ return 'true' at the end, so that your menu can be displayed
Also, see the Activity docs for onCreateOptionsMenu()
"This is only called once, the first time the options menu is displayed.
To update the menu every time it is displayed, see onPrepareOptionsMenu(Menu)."
If you want to add menu options to the Activity menu from within a Fragment you can also..
- override setHasOptionsMenu() in Fragment to return true
- override onCreateOptionsMenu() to add any items you like (just like you did at the Activity level)
- override onDestroyOptionsMenu()
The key thing here is that onCreateOptionsMenu() in Fragment is adding to the Activity menu.
It's hard to see without debugging exactly what's going on here but watch for calls to all of the above methods in Activity and Fragment and that will probably tell you what's going on.
If it is possible to control all menu options at the Activity level instead of the Fragment level, I would do that.
If not, and you need to use the Fragment menu methods, beware of Android's Fragment management (saving / restoring state)
Also, make sure your Fragments have an ID and/or tag.
(from the docs..)
"The fragment being instantiated must have some kind of unique identifier so that it can be re-associated with a previous instance if the parent activity needs to be destroyed and recreated. This can be provided these ways:
If nothing is explicitly supplied, the view ID of the container will be used.
android:tag can be used in <fragment> to provide a specific tag name for the fragment.
android:id can be used in <fragment> to provide a specific identifier for the fragment."
Finally, if all else fails, using Menu's findItem() before calling add() would be a safeguard, I suppose.
---------- Post added at 10:14 PM ---------- Previous post was at 09:52 PM ----------
Sorry caught in the crossfire - have only just seen your code.
I think much of the above applies.
Set the menu up in the Activity instead of the Fragment, if you can.
I would also consider using layout-port and layout-land to control your two different layouts.
Click to expand...
Click to collapse
Wow. thanks for that detailed answer. :good: (Why have I used all my thanks?)
I've always put it into the Activity as well but it might make sense to add it to the Fragment sometimes. For example if you need the same Fragment in multiple Activities...
In that case you'd need to add a listener to the item in the Fragment method though.
@PicomatStudio Thank you for the detailed answer, I really appreciate that =)
Now I'm creating the menu in the activity and I don't have to worry about the fragments life cycle anymore.
The only problem is: I didn't get the menuInflater for free here, I guess it's because of the fact that in the Fragment scenario, I had to use the Activity inflater, whereas here in the activity, I can get my own, with getMenuInflater().
Here's the way I modified it, now is in MainActivity.java.
Please report back if you find something strange
Code:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (getSupportFragmentManager().findFragmentByTag(CONTACT_LIST_FRAGMENT) != null)
getMenuInflater().inflate(R.menu.contact_list_fragment_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.addContactMenu:
onAddContactMenuOptionSelected();
default:
return super.onOptionsItemSelected(item);
}
}
domenicop said:
@PicomatStudio Thank you for the detailed answer, I really appreciate that =)
Now I'm creating the menu in the activity and I don't have to worry about the fragments life cycle anymore.
The only problem is: I didn't get the menuInflater for free here, I guess it's because of the fact that in the Fragment scenario, I had to use the Activity inflater, whereas here in the activity, I can get my own, with getMenuInflater().
Here's the way I modified it, now is in MainActivity.java.
Please report back if you find something strange
Code:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (getSupportFragmentManager().findFragmentByTag(CONTACT_LIST_FRAGMENT) != null)
getMenuInflater().inflate(R.menu.contact_list_fragment_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.addContactMenu:
onAddContactMenuOptionSelected();
default:
return super.onOptionsItemSelected(item);
}
}
Click to expand...
Click to collapse
I don't tend to use MenuInflater (just menu.add()..)
But looking at the docs it takes a Context so could you do..
Code:
new MenuInflater(this);
.. from your Activity ?
On a general design point the less your Activity depends on its Fragments the better, I reckon.
domenicop said:
The only problem is: I didn't get the menuInflater for free here, I guess it's because of the fact that in the Fragment scenario, I had to use the Activity inflater, whereas here in the activity, I can get my own, with getMenuInflater().
Click to expand...
Click to collapse
Well, you can get one:
Code:
getActivity().getMenuInflater();

Categories

Resources