Add/change compatibility SimpleMenu/MenuItem from compatibility Fragment - android

I realise this is a specific problem however I feel like others who are dealing with compatibility must have dealt with this.
As the user swipes through various fragments in the ViewPager I would also like the actionBar menu items to change. I am not sure if this is easily doable for the compatibility actionbar, any direction or help would be extremely appreciated. I am changing the title simply via setTitle() since the ActionBarHelper handles this however i cant find anything for updating the menu items. I tried the following but it fails..
public void setMenuDynamically(int resId){
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(resId, menu);
}
Looking through the code it seems there should be an easy/obvious way to get a handle to the SimpleMenu and add an item and set its icon.
Thanks in advance ( I am hoping the google boys are reading this as the android developers Google+ suggests)

Ok well please let me know if I suck as describing things or if there just is not much knowledge on this topic. If the first I am really sorry guys. Regardless I seemed to get this to work but am unsure if this is the correct way.
AcitonBarHelper
public void updateMenu(MenuItem item) {
}
ActionBarHelperBase (for 2.2 - 3.0 devices )
#Override
public void updateMenu(MenuItem item){
addActionItemCompatFromMenuItem(item);
}
And create similar methods for honeycomb and ICS
finally i have a listener for page changing and in that listener i call...
public void setMenuDynamically(int resId, String title){
MenuItem item = menu.add(title);
item.setIcon(resId);
getActionBarHelper().updateMenu(item);
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
}
I am not sure if the MenuItemCompat is necessary but I included it nonetheless. Everything seems to work great for 2.2 at least. I will most likely have to make changes in the Overrides but I can handle myself from here.

Related

menuItem.getActionView() == null in API 15

I'm supporting down to API 15 in my app, and I'm getting a crash for those users when I try to get the searchView from my menu.
Below is my code:
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
MenuItem menuItem = menu.getItem(0);
searchView = (SearchView)menuItem.getActionView();
searchView.setIconifiedByDefault(false);
searchView.setQuery("", true);
menuItem.expandActionView();
}
I'm getting a NullPointerException on this line:
searchView.setIconifiedByDefault(false);
because the searchView is null. This works perfectly fine on devices at API 16 and above. Has anyone run into this issue before?
While inflating a layout usually causes an immediate crash if there is a problem, inflating a menu resource does not. If there is some problem, a stack trace is logged, but otherwise the exception is handled, and so execution continues. It is only some time later that we realize that something did not work, when things break later on.
Custom action bar items (actionLayout, actionViewClass, actionProvider) are especially prone to this. If there is some problem loading any of those -- such as the actionViewClass not implementing the proper constructor -- we only find out about it when we try to retrieve the custom item and get null back. The solution is to rummage through LogCat and look for the stack trace associated with the handled exception, to see what really went wrong.
In an API level-dependent case, like this one, the most likely scenario would be where initialization of custom action item refers to a method that does not exist on the older version of Android, and therefore fails.
I also had just the same problem as you and came to this stackoverflow question. With some struggle, I have found the heart of this problem and a solution.
In API15, during app's initialization, only onCreateOptionsMenu is called but onPrepareOptionsMenu is not.
In API16 and later, onPrepareOptionsMenu is called right after onCreateOptionsMenu.
So my solution is to call onPrepareOptionsMenu at the ending point of onCreateOptionsMenu:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
(...)
if (Build.VERSION.SDK_INT < 16) {
onPrepareOptionsMenu(menu);
}
}

Can you add Chromecast functionality without using the ActionBar

I've been working from the example applications from Google to prepare our Chromecast capabilities,
What I've found however is that you are required to have a button in the ActionBar (as implemented by Google) in order to get an ActionProvider in order to attach your selector to.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.main, menu);
MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem);
mediaRouteActionProvider.setRouteSelector(mCaster.getMediaRouteSelector());
return true;
}
Intact, the entire example and API seems to be hot-wired to centre around the use of this button. I'm fine with reproducing the look and feel the Android are trying to go with here - but I use a custom ActionBar in my app which means I don't have any "hooks" to select the route et al.
Does anyone know how to work around this?
To begin with, I suggest you consider moving to appcompat actionbar so you can get all the benefits moving forward out of the box.
That said, the answer to your question is: yes, it is doable if you are willing to do a bit of extra work to manage the lifecycle and states yourself. I outline the steps here so you can create a working example for yourself. The requirements is to have appcompat and mediarouter from v7 support library in your project but you don't need to use any specific type of actionbar or no need to use the MediaRouteButton; in fact you can trigger the discovery and the rest in any shape or form that you want. Here are the steps:
Make sure appcompat and mediarouter from v7 support library are included in your dependencies. It is important to have v7 version of mediarouter
Do the usual thing, i.e. build a CastContext and set the stage ready for discovery (you need to create an instance of MediaRouteAdapter, which I have called myMediaRouteAdapter):
mCastContext = new CastContext(getApplicationContext());
MediaRouteHelper.registerMinimalMediaRouteProvider(mCastContext,
myMediaRouteAdapter);
mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mMediaRouteSelector = MediaRouteHelper
.buildMediaRouteSelector(MediaRouteHelper.CATEGORY_CAST,
"YOUR_APP_NAME", null);
mMediaRouterCallback = new MyMediaRouterCallback();
Start the discovery by calling the following in your, say, onStart():
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
In your custom callback MyMediaRouterCallback, listen for routes as they get added or removed. As routes get discovered, your onRouteAdded() method of your callback will be called and as they go away, the onRouteRemoved() will be called. It will be now your responsibility to hold on to the list of valid routes in your choice of data structure.
Lets say, for the sake of argument, you present the list to users in a dialog (makes sense, doesn't it?) where user sees a the name of route (i.e. device) in the UI and each item represents a RouteInfo. Then when a user clicks on a route, you need to call
mMediaRouter.selectRoute(info);
The above call results in another callback of your custom callback to be called, the onRouteSelected(). In that callback, call the following:
MediaRouteHelper.requestCastDeviceForRoute(info);
Finally, this will call the onDeviceAvailable() callback of the myMediaRouteAdapter and passes a CastDevice to you which you should be able to grab and use. When you are done with a route and want to "deselect" it, call
mMediaRouter.selectRoute(mMediaRouter.getDefaultRoute());
Hopefully that is enough to get you going.
I found better solution:
MediaRouteChooserDialog dialog =new MediaRouteChooserDialog(context);
dialog.setRouteSelector(mediaRouteSelector);
dialog.show();
Shows popup and will call onRouteSelected method on callback.

master/detail template with action menu - right way to show both

Beginner here, targetting sdk v14 and v17 for my learning...no need for older support.
I am using the master/detail template and trying to get an action menu (for SEARCH) to show up both in phone and tablet view. Actually I can get it to work, but I have to duplicate up my code in both ItemDetailActivity.java and ItemListActivity.java
These are the methods that I have to have in both for SEARCH to work:
public boolean onQueryTextChange(String newText) {
public boolean onQueryTextSubmit (String query) {
public boolean onClose () {
I only want to search the "detail", not the "list".
So my question: is there a way to associate the action bar with only the list fragment? That way I can keep the search functions in 1 file.
Thanks!
I'll go ahead and answer what I (think) I know as I don't want to leave this question open.
From tracing in the debugger, it looks to me like the phone activity and the tablet activity are separate and if you want to hook up an actionmenu, you have to hook it up to both separately.

Actionbar navigation

My android application targets the latest platform. I am new to the platform, and read bit conflicting information on actionbar. The way I was using it for navigation was.
menu.xml
<menu>
<item android:id="#+id/action_sort_size"
android:icon="#android:drawable/ic_menu_sort_by_size"
android:title="#string/action_barabc"
android:onClick="abc" />
<item android:id="#+id/action_sort_alpha"
....
In my activity
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void abc(MenuItem item) {
//...
}
this works, but the back/up navigation is not working correctly. could be unrelated, still like to confirm.
But, I also see implementation like here
where it switches on item.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menuitem1:
Toast.makeText(this, "Menu Item 1 selected", Toast.LENGTH_SHORT)
.show();
break;
case R.id.menuitem2:
....
}
Which is the better approach?
The better approach, in my opinion, is the switch approach. There aren't many reasons why, but I'll list them:
The code is centralized. You don't have x amount of methods that basically do the same thing. It keeps your code more readable; it is "cleaner". You also get a default statement using the switch, this can help if you mess up and forget to make a case specifically for an element in the layout.
If you really wanted to have a centralized method using xml, you would have onClick reference the same method and check the ids of the View parameter. Which is essentially the same asonOptionsItemSelected.
It is a part of the API. The Android engineers would not have made it a part of the API if they didn't want the developer to use it. Yes the XML is techinally API, but XML should be used more for layouts and visuals, not for logic.
Everyone uses it. All the tutorials I have seen and everyone's code uses this method. It is now more of a convention.
It's largely personal, but if it looks like it's a convention, and everyone uses it, I'd adhere to it. Especially if you're working as part of a team. Different coding styles for such arbritrary things should be avoided.
And concerning your back/up navigation, it shouldn't make a difference which way you do it, since you have to implement the same code to get that navigation type.

Manipulating with array adapter or with the underlaying data?

In the book The Busy Coders Guide to Android Development from CommonsWare, there is a chapter explaining how to work with the context menus.
In one example in that chapter, the context menu offers option for removing item from a list view that is generated from an ArrayList<String> object named words.
In the example the onContextItemSelected method is implemented like this:
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
ArrayAdapter<String> adapter=(ArrayAdapter<String>)getListAdapter();
switch (item.getItemId()) {
case R.id.remove:
adapter.remove(words.get(info.position));
return true;
default:
...
}
The line where adapter.remove(...) is called seems strange to me because of following fact:
Let's say the words object contains following items (in that order)
alfa
beta
gama
alfa
Now, when user loads the context menu upon the 2nd alfa and selects the option for removing it, the mentioned line actually removes the 1st alfa. And that seems wrong to me.
Instead, I would do something like this:
...
words.remove(info.position);
adapter.notifyDataSetChanged();
...
I'm not that good in Java and Android programming, so I would like to hear your opinion to this, because I want to be sure I understand well how adapters should be used.
Your idea sounds good.
The example is defunct if it behaves like you have described and you should tell Mark about it so he can check it as well (he'll probably do it anyway since he is very active on this site).

Categories

Resources