Calling the onMapClick() action from another button action - java

I would like to trigger the onMapClick() action on my map by pressing a button and sending it the required parameter. The following is run whenever the map is touched:
#Override
public void onMapClick(LatLng point) {
// animate camera to centre on touched position
mMap.animateCamera(CameraUpdateFactory.newLatLng(point));
// Adding new latlng point to the array list
markerPoints.add(point);
// Creating MarkerOptions object
MarkerOptions marker = new MarkerOptions();
// Sets the location for the marker to the touched point
marker.position(point);
}
I would like this button to replicate the same action as touching the screen except I am manually passing in a value:
mButtonCompleteLoop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onMapClick(markerPoints.get(0));
}
});
An error is appearing saying that onMapClick() cannot be resolved. Is there a certain way to do this? Or is it better to extract the onMapClick() code into a separate method that can then be called from both?

It is difficult to guess about reasons without looking on whole code of your activity/fragment
Maybe you set your map listener as anonymous class.
If so, instead of:
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
//this
}
});
You should make your activity implements GoogleMap.OnMapClickListener and set listener like this
mMap.setOnMapClickListener(this);
Then you can call OnMapClick from any place

Related

Is there a way to summarize multiple OnClickListener into one function in AndroidStudio?

I got multiple OnClickListener for 8 ImageViews with the same logic behind. OnClick Variable-Details will be shown. I tried to summarize them in a method and tried to add them in the OnCreate method with a Loop. But it did not work. Now I have 8 listeners and also 8 addListener at onCreateMethod.
Is there a more elegant way?
private void addListenerCal1Arrow() {
ivCalArrow1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!cal1Clicked) {
cal1Clicked = true;
ivCalArrow1.setImageResource(R.drawable.arrow_symbol_up);
tvDescription1.setVisibility(View.VISIBLE);
} else {
cal1Clicked = false;
ivCalArrow1.setImageResource(R.drawable.arrow_symbol_down);
tvDescription1.setVisibility(View.GONE);
}
}
});
}
more explanation:
I got an experiment Fragment, where i can add 8 Variables max. Each variable has several textviews and also an ImageView, which holds further information about the variable. when the ImageView is Clicked it shall show the information. I got an container class holding all the widgets of a variable, like the textviews and the imageview and also the description which shall be displayed when its clicked
There are 2 level to summrize this code
1- use 1 onClick() for all ImageViews: this involves
1.a implementing OnClickListener and not using anonymous inner class
make your activity or fragment implements OnClickListener and override onClick()
public class MyActivity extends Activity implements OnClickListener {
//class implementation
#override
public void onClick(View view){
}
}
use this as OnClickLister for method setOnClickListener():
ivCalArrow1.setOnClickListener(this);//this here refers to MyActivity
ivCalArrow2.setOnClickListener(this);//this here refers to MyActivity
//and so on ...
b. recognize the click source (which ImageView) generated the action)
you will need to compare view id with the 8 ImageViews id and execute proper code based on that:
#override
public void onClick(View view){
if(view.getId() == ivCalArrow1.getId()){
//do what needed on ivCalArrow1
}else if(view.getId() == ivCalArrow2.getId()){
//do what needed on ivCalArrow2
}
//and so on ... for 3 4 5 6 7 8
}
2- make onClick() general to handle the click properly: this involves using arrays instead of single variables named with 1 2 3, like cal1Clicked cal2Clicked ... or tvDescription1, tvDescription2 ...
this can be done in several ways, it could be complex to understand or maintain, so try to make it clear
you might need a Map where ImageView.getId as key and some value based on what you need
for example,
boolean variables calXClicked may be you can use a HashMap, that the key is an identifier for calX and the value is boolean for the clicked status
from my understanding the identifier for cal1Clicked is the imageView itself ivCalArrow1 so:
declare this class-scope
HashMap<int, boolean> calClickedStatus = new HashMap();
an at onCreate() add this:
//assuming all boolean values are false on first create of activity
calClickedStatus.put(ivCalArrow1.getId,false);
calClickedStatus.put(ivCalArrow2.getId,false);
calClickedStatus.put(ivCalArrow3.getId,false); // and so on
now at onClick() you will use view.getId as key to lookup other data needed
no need to find what is the source of the click, because you will look it up using the key (view.getId)
#override
public void onClick(View view){
if (!calClickedStatus.get(view.getId())) {
calClickedStatus.put(view.getId(), true);
//the view here is actually the clicked ImageView, so just cast it and use it, replace this
//ivCalArrow1.setImageResource(R.drawable.arrow_symbol_up);
//with this
((ImageView)view).setImageResource(R.drawable.arrow_symbol_up);
//now for this, you may want to use an array of TextView to hold tvDescription1, tvDescription2 ...
//and make a map to link each tvDescriptionX to the index of licked image
tvDescription1.setVisibility(View.VISIBLE);
} else {
//do same changes here too
calClickedStatus.put(view.getId(), false);
ivCalArrow1.setImageResource(R.drawable.arrow_symbol_down);
tvDescription1.setVisibility(View.GONE);
}
}
as i mentioned earlier this could be complex and might be hard to explain
and it could be done in may ways, so this is just to guide you on the concept and the rest is up to you
You can define in your layout for each View the following:
android:onClick="myClickFct"
android:clickable="true"
and also in the class which loads the layout the method:
public void myClickFct(View view){
...
}

Do I need to add many methods, or is it possible to call one method

I have a tic tac toe app, and I want to know whether it is possible to set all the tic tac toe buttons to one on_click event, and then create a variable to get the ID of the button clicked, then pass it as a parameter to another method which will do the actual functionality, OR do I need to create different on_click events for each button?
You can do something like this, and add as many "cases" as needed:
View.OnClickListener sharedClickHandler = new View.OnClickListener() {
public void onClick(View view) {
switch(view.getId()) {
case R.id.button1:
// handle first button
break;
case R.id.button2:
// handle second button
break;
}
}
}
You can just use one listener - the onClick method takes a View parameter, which is the view that was clicked on. You can then find out which of your buttons that was:
View.OnClickListener sharedClickHandler = new View.OnClickListener() {
public void onClick(View view) {
int id = view.getId();
// Do the right thing based on the ID
}
}
Exactly how you do what you need to do based on the ID is up to you. For simple examples you could just use a switch/case statement; in other cases if you're mapping from ID to something else (a mutable object representing game state for example) you could use a Map<Integer, GameObject> and just get the right one...
hello you can use the same click event for button, you can attach for example an integer as a tag to the button so that you can know which button was clicked and handle accordingly.
button1.setTag(1);
button2.setTag(2);
button3.setTag(3);
button1.setOnClickListener(buttonClick());
button2.setOnClickListener(buttonClick());
button3.setOnClickListener(buttonClick());
public View.OnClickListener buttonClick(){
View.OnClickListener click = new View.OnClickListener() {
#Override
public void onClick(View v) {
int numberClicked = v.getTag();
//You have now the button clicked
}
};
return click;
}

Cannot refer to a non-final variable pcurl1 inside an inner class defined in a different method

Doing an Application whcoh displays Markers on a Google Maps Fragment and opens a link in a browser on click, but i have a single marker where i dont want this to happen.
GoogleMap mMap;
mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.fragment1)).getMap();
mMap.addMarker(new MarkerOptions()
.position(new LatLng(lat3, lng3))
.snippet(bud1)
.title(name1));
mMap.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker marker) {
Uri uriUrl = Uri.parse(pcurl1);
Intent launchBrowser = new Intent(Intent.ACTION_VIEW, uriUrl);
startActivity(launchBrowser);
}
});
Now i want to implement a if (.... != "Your Position") in the onInfoWindowClick() but I have no Idea how to check the Marker for this content inside the marker.
Edit: New Problem occured which is "Cannot refer to a non-final variable pcurl1 inside an inner class defined in a different method" and if I set it final it destroys it's funktion becasue it is set inside a loop.
addMarker method returns a Marker object. For your location marker, save if as a field e.g. myLocationMarker and in the callback do
if (!marker.equals(myLocationMarker)) {
// ...

Android Notification Area Customization

I don't know whether this question get minus points, but I searched every where and my last resort is stackoverflow.
I need to add five buttons to notification area in horizontally. And each button I need to add even listener. I know it is possible to do with RemoteViews. But I never seen anyone adding event listener to each element.
These are the references if anyone need to refer.
Notifications Documentation
How to create a custom notification on android
SlidingDrawer API
You can add 5 anonymous listeners, or a single named listener.
Anonymous:
Button b1 = new Button(...);
b1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// first listener's code goes here
}
});
Button b2 = new Button(...);
b2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// second listener's code goes here
}
});
...
named is much the same, but contains a switch statement to differentiate what happens:
View.OnClickListener myListener = new View.OnClickListener() {
public void onClick(View v) {
String buttonTitle = ((Button)v).getText();
if ("title1".equals(buttonTitle)) {
// do things for the first button's click
} else if ("title2".equals(buttonTitle)) {
// do things for the second button's click
}
...
}
});
...

How do I handle screen orientation changes when a dialog is open?

I have an android app which is already handling changes for orientation, i.e. there is a android:configChanges="orientation" in the manifest and an onConfigurationChange() handler in the activity that switches to the appropriate layout and preps it. I have a landscape / portrait version of the layout.
The problem I face is that the activity has a dialog which could be open when the user rotates the device orientation. I also have a landscape / portrait version of the dialog.
Should I go about changing the layout of the dialog on the fly or perhaps locking the activity's rotation until the user dismisses the dialog.
The latter option of locking the app appeals to me since it saves having to do anything special in the dialog. I am supposing that I might disable the orientation when a dialog opens, such as
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
and then when it dismisses
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
Would that be a sensible thing to do? If the screen orientation did change while it was locked, would it immediately sense the orientation change when it was unlocked?
Are there alternatives?
I would recommend not turning off the screen rotation, instead of this handle the configuration changes for the Dialog. You could use one of these two approach for this:
The first one is using a flag variable in onSaveInstanceState(outState) method, and restore the dialog onCreate(bundle) method:
in this example my flag variable is called 'isShowing Dialog', when the onCreate method is called by the android System for first time, the bundle argument will be null and nothing happens. However when the activity it's recreated by a configuration change (screen rotation), the bundle will have the boolean value isShowing Dialog, previously saved by the inSaveInstanceState(...) method, so if the variable gets true the dialog is created again, the trick here is set the flag in true when the dialog get showing, and false when it's not, is a little but simple trick.
Class MyClass extends Activity {
Boolean isShowingDialog = false;
AlertDialog myDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
if(savedInstanceState!=null){
isShowingDialog = savedInstanceState.getBoolean("IS_SHOWING_DIALOG", false);
if(isShowingDialog){
createDialog();
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("IS_SHOWING_DIALOG", isShowingDialog);
super.onSaveInstanceState(outState);
}
#Override
protected void onPause() {
if(myDialog!=null && myDialog.isShowing()) {
myDialog.dismiss();
}
}
private void createDialog() {
AlertDialog.Builder dialog_builder = new AlertDialog.Builder(this);
dialog_builder.setTitle("Some Title"):
... more dialog settings ...
myDialog = dialog_builder.create();
myDialog.show();
isShowingDialog = true;
}
private void hideDialog(){
myDialog.dismiss();
isShowingDialog = false;
}
}
The second approach is to use the ability of the fragments components to retain its states, the main idea is create the dialog inside a fragment, there is the problem about detach and reattach the fragment during the configuration changes (because you need dismiss and show the dialog correctly), but the solution is very similar to the first approach. The advantage of this approach is that if you have an AlertDialog with a couple of configurations, when the fragment is recreated there is not needed to create and setting up the dialog again, only make it show() and the AlertDialog state is maintained by the fragment.
I hope this helps.
I suggest your Dialog should override onSaveInstanceState() and onRestoreInstanceState(Bundle) to save its state into a Bundle.
You then override those methods in your Activity, checking if the Dialog is shown and if so - calling the dialog's methods to save and restore it's state.
If you are displaying this dialog from a fragment, you will want to override OnActivityCreated(Bundle) instead of OnRestoreInstanceState.
For a source example see the built-in clock app provided with Android, where the SetAlarm Activity handles the TimePickerDialog this way.
If you are handling orientation changes yourself, then here is an approach.
I won't claim that this is an elegant solution, but it works:
You can keep track of whether the dialog has an active instance inside the dialog class itself, by using a static variable activeInstance, and overriding onStart() to set activeInstance = this and onCancel() to set activeInstance = null.
Provide a static method updateConfigurationForAnyCurrentInstance() that tests that activeInstance variable and, if non-null, invokes a method activeInstance.reInitializeDialog(), which is a method that you will write to contain the setContentView() call plus the code that wires the handlers for the dialog controls (button onClick handlers, etc. - this is code that would normally appear in onCreate()). Following that, you would restore any displayed data to those controls (from member variables in your dialog object). So, for example, if you had a list of items to be viewed, and the user were viewing item three of that list before the orientation change, you would re-display that same item three at the end of updateConfigurationForAnyCurrentInstance(), right after re-loading the controls from the dialog resource and re-wiring the control handlers.
You would then call that same reInitializeDialog() method from onCreate(), right after super.onCreate(), and place your onCreate()-specific initialization code (e.g., setting up the list of items from which the user could choose, as described above) after that call.
This will cause the appropriate resource (portrait or landscape) for the dialog's new orientation to be loaded (provided that you have two resources defined having the same name, one in the layout folder and the other in the layout-land folder, as usual).
Here's some code that would be in a class called YourDialog:
ArrayList<String> listOfPossibleChoices = null;
int currentUserChoice = 0;
static private YourDialog activeInstance = null;
#Override
protected void onStart() {
super.onStart();
activeInstance = this;
}
#Override
public void cancel() {
super.cancel();
activeInstance = null;
}
static public void updateConfigurationForAnyCurrentInstance() {
if(activeInstance != null) {
activeInstance.reInitializeDialog();
displayCurrentUserChoice();
}
}
private void reInitializeDialog() {
setContentView(R.layout.your_dialog);
btnClose = (Button) findViewById(R.id.btnClose);
btnClose.setOnClickListener(this);
btnNextChoice = (Button) findViewById(R.id.btnNextChoice);
btnNextChoice.setOnClickListener(this);
btnPriorChoice = (Button) findViewById(R.id.btnPriorChoice);
btnPriorChoice.setOnClickListener(this);
tvCurrentChoice = (TextView) findViewById(R.id.tvCurrentChoice);
}
private void displayCurrentUserChoice() {
tvCurrentChoice.setText(listOfPossibleChoices.get(currentUserChoice));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
reInitializeDialog();
listOfPossibleChoices = new ArrayList<String>();
listOfPossibleChoices.add("One");
listOfPossibleChoices.add("Two");
listOfPossibleChoices.add("Three");
currentUserChoice = 0;
displayCurrentUserChoice();
}
#Override
public void onClick(View v) {
int viewID = v.getId();
if(viewID == R.id.btnNextChoice) {
if(currentUserChoice < (listOfPossibleChoices.size() - 1))
currentUserChoice++;
displayCurrentUserChoice();
}
}
else if(viewID == R.id.btnPriorChoice) {
if(currentUserChoice > 0) {
currentUserChoice--;
displayCurrentUserChoice();
}
}
Etc.
Then, in your main activity's onConfigurationChanged() method, you would just invoke YourDialog.updateConfigurationForAnyCurrentInstance() whenever onConfigurationChanged() is called by the OS.
Doesn't seem the title was ever resolved (Google Necro Direct).
Here is the solution, matching the request.
When your activity is created, log the screen orientation value.
when onConfiguration change is called on your activity, compare the orientation values. if the values don't match, fire off all of your orientation change listeners, THEN record the new orientation value.
Here is some constructive code to put in your activity (or any object that can handle configuration change events)
int orientation; // TODO: record orientation here in your on create using Activity.this.getRequestedOrientation() to initialize!
public int getOrientation(){return orientation;}
public interface OrientationChangeListener {
void onOrientationChange();
}
Stack<OrientationChangeListener> orientationChangeListeners = new Stack<>();
public void addOrientationChangeListener(OrientationChangeListener ocl){ ... }
public void removeOrientationChangeListener(OrientationChangeListener ocl){ ... }
That's the basic environment. Here's your executive:
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (orientation != newConfig.orientation)
for (OrientationChangeListener ocl:orientationChangeListeners) ocl.onOrientationChange();
orientation = newConfig.orientation;
}
In YOUR code model, you may need to send the new configuration, with the event, or the two orientation values with the event. However, Activity.this.getOrientation() != Activity.this.getRequestedOrientation() during event handling (because we are in a logical state of change between two logical values).
In review of my post, i have determined that there could be some synchronization issues, with multiple events! This is not a fault of this code, but a fault of "Android Platform" for not having defacto orientation sense handlers on every window, thusly trashing the polymorphic benefits of using java in the first place..
See the answer from Viktor Valencia above. That will work perfectly with the slight adjustment that you move the createDialog() to onResume.
#Override
protected void onResume() {
super.onResume();
if(isShowingDialog){
createDialog();
}
}
Fetch the boolean isShowingDialog value at onCreate, as suggested, but wait for onResume to display the dialog.

Categories

Resources