How to call for a method from OnCreate with menu item? - android

I'm building an app with option to load a work space from remote (via ADB), using this code in OnCreate:
Bundle extras = this.getIntent ( ).getExtras ( );
if (extras != null && extras.containsKey("workspace"))
{
String param = extras.getString("workspace");
WSmethods.loadWorkspace(param); //work space methods class
}
This work space effect save menu item, therefore my workspace constractor contain this menu item, like this:
public workspaceMethods(MyActivity myActivity, MenuItem saveItem)
but, in order to receive MenuItem I have to wait for onCreateOptionsMenu method that called after OnCreate
Therefore, I found myself in a tangle: On the one hand I have to call my work space methods in OnCreate (in order to receive commands from ADB) and on the other hand I have to receive my menu item that initialize after OnCreate called.
Bottom line, the question: How can I call for method from OnCreate with a menu item? (to be more accurate, in my case the question is how to initialize class variable with menu item in OnCreate method?)
EDIT I initialize WSmethods like this (in onCreateOptionsMenu):
WSmethods = new workspaceMethods(this, menu.findItem(R.id.action_save));

You have all access to intent extras even from onCreateOptionsMenu. So just call your method from it - after inflating your menu.

EDIT:
I'm just going to restart as I was under the impression you were implementing the fragment framework.
try this:
#Override
public void onPostCreate(Bundle savedInstance)
{
super .onPostCreate(savedInstance);
WSmethods = new workspaceMethods(this, menu.findItem(R.id.action_save));
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
int id = item.getItemId();
switch (id)
{
case R.id.action_save:
WSmethods = new workspaceMethods(Activity.this, item);
//do actions associated with method
break;
//other switch cases
default:
//implement a default action
break;
}
}

Related

ToolBar Spinner Odd Behavior

I am using a ToolBar Spinner to switch among the 6 activities of my App. The opening activity, which I call MainView, has only the spinner [plus a help link on the ToolBar action menu]. The user selects from the spinner which of the other 5 activities he wishes to run and when finished uses the ToolBar back button of that activity to return to MainView.
It all works fine except, after returning to MainView from any of the other activities, the name of that activity remains displayed in the Spinner, not MainView as i had expected. Plus, if user wants to return to that same activity he must select any of the others first.
I had thought that when the App returns to MainView using the ToolBar back button it would do so by calling the MainView OnCreate, and the MainView spinner would be recreated thus displaying MainView. But this appears to be not the case.
I have tried a few things including setSelection(0) in onCreate, re-initializing the spinner in onStart and onResume - but none has made a difference. Hope you can help.
xml for spinner ...
<Spinner
android:id="#+id/spinner_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
initialization code for spinner
String[] mainview_names = new String[]
{"MainView", "WebView", "JsoupView", "CodeView", "Connectivity", "FtpView"};
Spinner mainSpinner = (Spinner) findViewById(R.id.spinner_main);
ArrayAdapter<String> adapter = new ArrayAdapter<>
(this,android.R.layout.simple_spinner_dropdown_item, mainview_names);
mainSpinner.setAdapter(adapter);
mainSpinner.setOnItemSelectedListener(new CustomOnItemSelectedListener());
// mainSpinner.setSelection(0);
The Listener ...
public class CustomOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
switch (pos){
case 0: // Main View
break;
case 1: // Web View
BrowseWWW();
break;
case 2: // Jsoup View
LoadHTMLJsoup();
break;
case 3: // Code View
LoadHTMLCode();
break;
case 4: // Connectivity
GetHTMLConn();
break;
case 5: // Ftp View
GetHTMLFtp();
break;
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
}
EDIT: Additional information:
The 5 activities each respond to the back button with code structured like this.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
help.setVisibility(View.GONE);
switch (item.getItemId()){
case android.R.id.home: // up navigation
finish();
return true;
case R.id.load:
// ....
}
return true;
case R.id.Clear
// ...
return true;
}
return false;
}
#Override
public void finish() {
Intent i = new Intent();
i.putExtra("urlKey", url.getText().toString());
i.putExtra("tokenKey", token.getText().toString());
i.putExtra("redirectsKey", HttpURLConnection.getFollowRedirects());
setResult(RESULT_OK, i);
super.finish();
}
Ok the spinner state issue:
Without digging into more of your code, here's my theory:
You're in activity A. You select something in the spinner, say B. Now you're in activity B and activity A is paused retaining state it had -- i.e. it has the item corresponding to B selected in the spinner. When you go back from B, activity A is resumed in that exact state and, of course, still has the B item in the spinner. You can't go to B again right away, because if you re-select B, your select handler will not be called (since there's no change).
The fact that Activity is not destroyed every time is probably what tricked you, that's why you should take a look at google guide on Activities -- it will probably save you a lot of guessing time :)
So, to fix your issue with spinners, you should override the onResume() method of each activity and use it to set the spinner to the state corresponding to that activity -- that's the short version.
Long version is, you're probably going somewhat against the flow using toolbar spinner to navigate between activities.
Navigation can be faster and more intuitive you implement your Web, Jsoup, Code and other top-level views as Fragments (also, this) inside a single Activity, that's exactly what they're for. It'll probably be more user-friendly to use Tabs instead of Spinner.

Android activity to a fragment control transfer

I am creating an android application with three tabs using PageSlidingtabStrip as a library to create a swipe view.And it has three fragments.Each fragments has a list view.When the item of the listview is clicked it opens an activity and display the details.
The problem is how can i come back to the fragment in the main screen using back button in actionbar in the activity
And how can i go to the corresponding Fragment(Tab)
Try something like this :
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
Intent intent = new Intent(YourCurrentClass.this , ClassThatYouWantToGo.class);
startActivity(intent)
}
Or actually like #TommyTopas said, you can just Override onBackPressed and put this.finish();.
EDIT
As I've understood you want to use a button on your AcitonBar, then you have tod o something like this :
First set the HomeButton enabled doing :
getActionBar().setDisplayHomeAsUpEnabled(true); Then Override onOptionsItemSelected
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// or onBackPressed();
this.finish()
}
return true;
}
As I understand, when you return to the "Tab" Activity, you want to display the same tab in which the list item had been clicked. What you can do is, when a list item in any tab is clicked, save the tab number in onSavedInstanceState(), and when the Activity is recreated, then set the previously selected tab (if one was selected previously). You will get the savedInstanceState that you saved in onSavedInstanceState() back in the onCreate() of the same Activity.
You can provide an Up navigation by writing getActionBar().setDisplayHomeAsUpEnabled(true); and then in the onOptionsItemSelected method in the activity, if the item's id is android.R.id.home call the activity's method onBackPressed(); which will close your current activity and come back to your fragment

Couldn't resolve menu item onClick handler

Im stuck and just exhausted, what am I doing wrong here and what do I need to do to get it to work right? Thanks
API 11.
I setup a item in menu.xml:
<item android:id="#+id/action_add_shindig"
**android:onClick="showCamera"**
android:icon="#drawable/shindig_new"
android:title="#string/shindig_new"
android:showAsAction="ifRoom" />
And in mainActivity I added a method to fire off an intent for the camera in another Activity.
/**
* Method to handle launching the Camera view activity.
* #param view
*/
public void showCamera(View view) {
}
But I get this error:
Couldn't resolve menu item onClick handler showCamera in class com.shindiggy.shindiggy.MainActivity
I resolved it by changing the method to onCameraClick(MenuItem item) and updating the onClick to reflect its name "onCameraClick".
It seems you already solved it, but this is something that has troubled me and is definitely something you would like to read the answer to in the actual documentation. (Just to make sure whatever fix you come up with works on all phones - not just your own...)
Look here: https://developer.android.com/guide/topics/resources/menu-resource#item-element
The android:onClick property of a item in the menu needs a public method with MenuItem as its parameter.
Note that this is different from, say, a Button!
http://developer.android.com/reference/android/widget/Button.html
http://developer.android.com/reference/android/R.attr.html#onClick
Here, a method taking View as its parameter is needed.
I don't believe menuItem has an onClick(). Use onOptionsItemSelected instead. Use themenuItemid` to know which item was clicked.
Menu Docs
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.action_add_shindig:
// run your showCamera code or call that method
return true;
Handling click events
That is for an OptionsMenu but it also discusses ContextMenus
dont use OnClick Method .
use if statement in Method below:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
else if (id==R.id.action_other)
{
Toast toast=Toast.makeText(this, "Other Clicked.", Toast.LENGTH_LONG);
toast.show();
}
else if (id==R.id.action_Exit)
{
finish();
}
return super.onOptionsItemSelected(item);
}
According to Android Doc - https://developer.android.com/guide/topics/resources/menu-resource#item-element
android:onClick
Method name. The method to call when this menu item is
clicked. The method must be declared in the activity as public and
accept a MenuItem as its only parameter, which indicates the item
clicked. This method takes precedence over the standard callback to
onOptionsItemSelected(). See the example at the bottom.
Warning: If
you obfuscate your code using ProGuard (or a similar tool), be sure to
exclude the method you specify in this attribute from renaming,
because it can break the functionality.
Introduced in API Level 11.

OnOptionsItemSelected in activity is called before onOptionsItemSelected in fragment. Other way possible?

I have an activity which can contain several fragments. Each of the fragments can have their own menu entries in the ActionBar. This works fine so far and each item is clickable and performs the desired action.
My problem is the following. In the MainActivity I declared the following lines to intercept calls to the HomeIcon of the ActionBar:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
clearBackStack();
setHomeFragment();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
I declared it in the Activity because I wanted that every Fragment should call this so that I don't have to catch the android.R.id.home case in each fragment.
In one Fragment I am using setDisplayHomeAsUpEnabled(true), so that I get the little arrow left of the ActionBar Icon. When the HomeIcon is clicked in this fragment I don't want to set the HomeFragment, I want to set the Fragment which was last displayed. So I have a onOptionsItemSelected - Method in the Fragment:
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case android.R.id.home:
setLastFragment();
return true;
...
However this does not work the way I wanted it to work. The Activity's onOptionsItemSelected is called first, catches the MenuItem and redirects to the HomeFragment. With the other MenuItems declared in other fragments i can check the see the same behaviour. Activity is called first, doesn't catch the MenuItem (default case) and then redirects to super.onOptionsItemSelected(item).
So it seems that this is the case how Android handles the Menu Clicks. First Activity, then Fragment. Is there a way to change this? I don't want to put the android.R.id.home-case in every fragment and handle it there. Is there a nicer way to do this?
I just encounter this problem, and I have made it work using following code.
In the activity's onOptionsItemSelectedfunction, add:
if (id == android.R.id.home){
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);
if(null != currentFragment && currentFragment.onOptionsItemSelected(item)){
return true;
}
}
And in the fragment's onOptionsItemSelected method, you handle the corresponding things.
In this way, if the fragment has any things to do for the menu item, it will do it and return true to stop any other process.
And if the fragment does not have anything to do with this item, it will return false or call super.onOptionsItemSelected method which may eventually return false to let others process it.
According to the developers reference,
"Return false to allow normal menu processing to proceed, true to consume it here."
So I would try returning 'false' by default in the Activity's implementation of onOptionsItemSelected(), this way the event will pass on to the Fragment's implementation if it is not caught.
Not sure if it's possible. In the official docs available here:
http://developer.android.com/guide/topics/ui/actionbar.html#ActionEvents
There is a note, that states the following:
[...] However, the activity gets a chance to handle the event first, so the system first calls onOptionsItemSelected() on the activity, before calling the same callback for the fragment.
You can do as #Surely written, it's great idea, but in that case you will call onOptionsItemSelected on fragment without knowing which fragment it is, and you should override onOptionsItemSelected method in all your fragments.
If you only want to call this method for particular fragments, you should find them by tag, which you used when adding them:
case android.R.id.home:
Fragment frag = getSupportFragmentManager()
.findFragmentByTag(FRAGMENT_TAG);
if(frag != null && frag.isVisible() && frag.onOptionsItemSelected(item)) {
return true;
Tag is specifying like this:
fragmentManager.beginTransaction()
.add(containerId, fragment, FRAGMENT_TAG)

Loader calls onLoadFinished before Activity's onCreateOptionsMenu

When an AsynctaskLoader is initiated from Activity's OnCreate(), it finishes its work and calls onLoaderFinished() before action bar menu is inflated, that is before onCreateOptionsMenu() is called.
I need to alter some action menu items depending on results of loader. What approach might resolve this ?
UPDATE:
This happens On orientation change. I'm Observing this sequence in debugger:
Application Start: onCreate() -> onCreateOptionsMenu() -> onLoadFinished()
Rotate to landscape: onCreate() -> onLoadFinished() -> onCreateOptionsMenu()
Rotate back to portrait: onCreate() -> onLoadFinished() -> onCreateOptionsMenu()
I ran into the same scenario when trying to call shareActionProvider.setShareIntent() in onLoadFinished() which was dependent on shareActionProvider being initalized in onCreateOptionsMenu().
My solution was to scope both my Intent and ShareActionProvider to the Fragment, and then within each method initialize the appropriate field and set the other if it had already been defined. That way it works no matter which is called first without invalidating the menu.
Here's basically what it looks like
public class myFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
...
private ShareActionProvider shareActionProvider;
private Intent shareIntent;
...
onCreateOptionsMenu()
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_my_fragment, menu);
MenuItem menuItem = menu.findItem(R.id.action_share);
shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menuItem);
//in the case where onLoadFinished is called first, simply set the share intent here.
if (null != shareIntent)
{
shareActionProvider.setShareIntent(shareIntent);
}
}
onLoadFinished()
#Override
public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor data) {
... <get some data from cursor> ...
shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_text)+data);
//shareActionProvider may be null due to onLoadFinished called before onCreateOptionsMenu
if (null != shareActionProvider)
{
shareActionProvider.setShareIntent(shareIntent);
}
I need to alter some action menu items depending on results of loader. What approach might resolve this ?
Your scenarios #2 and #3 should be perfectly fine for you, then. By the time onCreateOptionsMenu() is called, you have your Cursor (or whatever) from your Loader and can tailor what you do in onCreateOptionsMenu().
With regards to scenario #1, have onCreateOptionsMenu() do the most likely thing, and if you determine in onLoadFinished() that this is incorrect, call invalidateOptionsMenu() to force another call to onCreateOptionsMenu(), I suppose.
This particular approach avoids invalidating entire menu.
Define one boolean flag, and one MenuItem variable for each item you want to control based on outcomes of loader results:
Let's say you want to enable New action only if loader returns any success:
private boolean mEnableNew = false;
private MenuItem mItemNew;
Save the menu item to variable when menu is created, also, apply state:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.manage_menu, menu);
mItemNew = menu.findItem(R.id.itm__manage_menu__new);
mItemNew.setEnabled(mEnableNew);
return super.onCreateOptionsMenu(menu);
}
Finally, obtain new settings based on Loader's results, and enable disable menu item:
#Override
public void onLoadFinished(Loader<BI_Result> loader, Result result) {
//--If onCreateOptionsMenu is not yet executed,it will use this boolean value when it does
mEnableNew = result.isSuccess();
//--If onCreateOptionsMenu has executed, we apply state here
if (mItemNew != null) {
mItemNew.setEnabled(mEnableNew);
}
}

Categories

Resources