This question already has answers here:
How are Anonymous inner classes used in Java?
(18 answers)
Closed 9 years ago.
second day in android self teachin and saw this code bleow.
from what I understood, it seems to me that the code is getting the button value
final Button GetServerData = (Button) findViewById(R.id.GetServerData);
and then I am not sure what happened. Being from php background this syntax looks very unfamiliar that a method is being called as a methods parameter in here
GetServerData.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// WebServer Request URL
String serverURL = "http://androidexample.com/media/webservice/JsonReturn.php";
// Use AsyncTask execute Method To Prevent ANR Problem
new LongOperation().execute(serverURL);
}
});
I also am not sure what View arg0 is.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.rest_ful_webservice);
final Button GetServerData = (Button) findViewById(R.id.GetServerData);
GetServerData.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// WebServer Request URL
String serverURL = "http://androidexample.com/media/webservice/JsonReturn.php";
// Use AsyncTask execute Method To Prevent ANR Problem
new LongOperation().execute(serverURL);
}
});
}
1) This is type casting, the method
findViewById returns something, the method
which called it casts the result to Button.
2) This an anonymous class, this is a class
implementing an interface, the class is defined
right there at the place of its usage.
3) The OnClickListener interface
apparently has one method called
onClick and it has one View argument.
This is what arg0 is. But it does not
seem to be used in the implementing class.
The name arg0 is not really important.
You can name it also x or y or anything else.
Related
This question already has answers here:
android.content.res.Resources$NotFoundException: String resource ID #0x0
(8 answers)
Closed 5 years ago.
I need to start the countdown timer in this activity. It should be started from the button. Below I bring the code snippets.
I think I did everything right, but it doesn't work - why is this?
public class Step5 extends AppCompatActivity {
Button mgo;
public TextView timer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.step5);
timer = (TextView) findViewById(R.id.timer);
mgo = (Button) findViewById(R.id.go);
mgo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new CountDownTimer(900000,1000) {
#Override
public void onTick(long millisUntilFinished) {
timer.setText((int)millisUntilFinished/1000);
}
#Override
public void onFinish() {
timer.setText("Done");
}
}.start();
}
});
}}
Button in xml
<Button
android:id="#+id/go"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#FF3D00"
android:textColor="#ffffff"
android:text="#string/Start"
android:layout_alignParentBottom="true"/>
The problem is in the timer.setText((int)millisUntilFinished/1000); part.
timer.SetText() needs a string as an argument.
So try the following
timer.setText(String.valueOf((int)millisUntilFinished/1000));
It will work 100 %.
The problem lies on the below code snippet:
timer.setText((int)millisUntilFinished/1000);
setText() method accepts only String as argument type while you are passing an int type of argument. So you could try to use the valueOf() static method of String class in order to convert your int value type into a String Object. Below is the suggested solution:
timer.setText(String.valueOf((int)millisUntilFinished/1000));
Nevertheless it should be noticed that if you compile you submitted code you will get the below compilation error:
error: incompatible types: int cannot be converted to String
This means that your code will be compiled with error and you will get noticed by the compiler for sure.
Additionally if you would use a Java IDE like Netbeans then you would get noticed for this error by a notification like below:
incompatible types: int cannot be converted to String
So concluding lets say that errors like these can be avoided by reading IDE's warnings and as a second step the compiler's messages.
The full text of the error is:
C:\Users\Dov\Google Drive\AndroidStudioProjects\FlagQuiz - Copy (2)\app\src\main\java\com\dslomer64\flagquiz\QuizFragment.java
Error: Fragments should be static such that they can be re-instantiated by the system, and anonymous classes are not static [ValidFragment]
To make it worse, it doesn't tell me which line the error is in. I had assumed, since it was mentioned above, that QuizFragment is at fault, but how? So I then concluded that QuizFragment was mentioned only to indicate which class the error is in.
Also, note that no line is flagged with error as the yellow square shows.
I found the word "anonymous" in 3 places in comments in the incomplete code segment below.
DialogFragment quizResults = new DialogFragment() // anonymously **********
// extend DialogFragment class
{
#Override public Dialog onCreateDialog(Bundle bundle)
{
...
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setPositiveButton
(
R.string.reset_quiz,
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id)
{
resetQuiz();
}
} // end anonymous inner class *******************
);
return builder.create(); // return the AlertDialog
} // end method onCreateDialog
}; // end DialogFragment anonymous inner class ****************
Is there something wrong (as of AS 2.3.3; nothing was wrong before upgrade) with DialogFragment quizResults = new DialogFragment() or the definition of builder, which contains an anonymous inner class?
If so, why no compilation errors? And in this case, how do I fix the problem?
(I don't want to just start hacking away at code I didn't write [I received project from an author and made many modifications] since there are at least 3 conceivable starting points and maybe none address the error(s?).
nothing was wrong before upgrade
Most likely, there was. Android Studio was not complaining about your code previously, but it may not have worked properly anyway. What changed is that now Android Studio is pointing out the problem, rather than you finding out the hard way in testing.
Is there something wrong... with DialogFragment quizResults = new DialogFragment()
Yes. It's impossible to recreate the fragment.
So, when the user rotates the screen, or changes locale, or night mode kicks in, or any number of other possible configuration changes, when Android destroys the fragment and tries to recreate it, it can't. Only the lines of code in your question can recreate the fragment, and those lines of code are yours, not the framework's, and it doesn't know about them.
It is possible that you have worked around this by blocking the ordinary destroy-and-recreate cycle for the activity, via android:configChanges. That itself is usually an anti-pattern, but if you legitimately need android:configChanges and are using it properly, you should be able to suppress this Lint error.
And in this case, how do I fix the problem?
Create a regular Java class for quizResults, extending DialogFragment and including your code. Then, use that Java class.
The part that is wrong is the following:
DialogFragment quizResults = new DialogFragment() {
#Override
public Dialog onCreateDialog(Bundle bundle) {
where you are defining an anonymous subclass of DialogFragment. This is the wrong way to use Fragments as suggested by the new lint check in Android 2.3.3.
Why? Instantiating Fragments like this will cause problems if you are using an Activity's FragmentManager.
The problematic situation is as follows: when Activity#saveInstanceState(Bundle outState) is called the FragmentManager will attempt to save the state of your Fragment. When subsequently the Activity's state is restored, the FragmentManager will attempt to recreate your Fragments (using no-args constructors) and set their states to the way they were before. This is not possible if you use anonymous subclasses of Fragment.
Henec, Fragments must have a no-args constructor and the preferred way of instantiating them is with static factory methods. Instead of anonymous subclasses, use Fragment#setArguments(Bundle bundle):
inside QuizFragment.java:
public static QuizFragment instantiate(Bundle args) {
QuizFragment frag = new QuizFragment();
frag.setArguments(args);
return frag;
}
I ran into this same problem. I converted the anonymous DialogFragment class into a regular class :
public DialogFragment instantiate(Bundle args){
DialogFragment quizResults = new DialogFragment();
quizResults.setArguments(args);
Dialog aDialog = createDialog(args);
aDialog.show();
return quizResults;
}
// create an AlertDialog and return it
public Dialog createDialog(Bundle bundle){
AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity());
builder.setCancelable(false);
builder.setMessage(
getResources().getString(
R.string.results, totalGuesses, (1000 / (double) totalGuesses)));
// "Reset Quiz" Button
builder.setPositiveButton(R.string.reset_quiz,
new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int id)
{
resetQuiz();
}
} // end anonymous inner class
); // end call to setPositiveButton
return builder.create(); // return the AlertDialog
} // end method createDialog
The original code block under onClick(View v):
///////////////////////////////////////////////////////////////////
DialogFragment quizResults = new DialogFragment()
{
// create an AlertDialog and return it
#Override
public Dialog onCreateDialog(Bundle bundle)
{
AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity());
builder.setCancelable(false);
builder.setMessage(
getResources().getString(R.string.results, totalGuesses, (1000 / (double) totalGuesses)));
// "Reset Quiz" Button
builder.setPositiveButton(R.string.reset_quiz,
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id)
{
resetQuiz();
}
} // end anonymous inner class
); // end call to setPositiveButton
return builder.create(); // return the AlertDialog
} // end method onCreateDialog
Was replaced with call to instantiate the DialogFragment as below:
DialogFragment quizResults = instantiate(mSavedInstanceState);
Thanks to #Commonsware and #David Rawson, I managed to make it work with static inner class for myDialogClass by changing anything the compiler griped about to static, which included several methods as well as many (every?) variable.
This posed one problem:
public static void loadNextFlag()
{
...
// display current question number--2nd and 3rd parameters are INPUT into the xml statement
questionNumberTextView.setText
(correctAnswers + 1) + //was ,
"/" + FLAGS_IN_QUIZ);
// AssetManager assets = getActivity().getAssets();
...
} // end method loadNextFlag
The line for formatting questionNumberTextView had to be changed to
questionNumberTextView.setText(
("" + (correctAnswers + 1)
"/" + FLAGS_IN_QUIZ);
because the original
questionNumberTextView.setText(getResources().getString
(R.string.question,
(correctAnswers + 1),
FLAGS_IN_QUIZ);
gave the static vs. non-static error for getResources. I just settled for not as great a format, but suitable.
I also made assets a global static variable to be assigned only once, in onCreateView.
So textbooks don't always do it right, since to do so would raise the level of the text too far above the intended audience.
Can I break the set-listener line into smaller pieces?
Here is the code I have:
protected void onCreate(Bundle savedInstanceState) {
Preference button = (Preference)getPreferenceManager().findPreference("exitlink");
button.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
finish();
return true;
}
});
I would like this to look something like:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Preference button = (Preference)getPreferenceManager().findPreference("exitlink");
if(button != null) {
button.setOnPreferenceClickListener(onPreferenceClick);
}
}
public boolean onPreferenceClick(Preference arg0) {
finish();
return true;
}
You can also create a variable outside of your method:
private Preference.OnPreferenceClickListener listener = new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
finish();
return true;
}
};
Then you use it as a variable: setListener(listener). This would allow you to have multiple instances of the same listener class in your Activity.
Your code above nearly works already. Use your above code with this tiny change:
button.setOnPreferenceClickListener(this);
Then you just let your class implement the specific interface needed, in this case Preference.OnPreferenceClickListener.
In addition to dmon's suggestion below about using variables for this, it is also possible to write a function that returns a listener, which is very useable when you want to have similar listeners but with slight changes, like in the example below.
private Preference.OnPreferenceClickListener getListener(int listenerId) {
return new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference arg0) {
Log.i("MyTag", "Listener " + listenerId + " invoked!");
finish();
return true;
}
};
}
As others have mentioned, even though you cannot pass a method name to setOnPreferenceClickListener you can create a variable of a type that extends Preference.OnPreferenceClickListener. In your original code, that is actually exactly what you are doing: you are creating an object of an anonymous inner class.
The advantage of this approach, say over Simon André Forsberg's answer above is of scope: it keeps the listener functionality in that small block, instead of potentially all over the class.
Creating a separate variable outside the method as in dmon's answer loses one big benefit of the anonymous inner class, that they can access the variables in the containing scope: in your original code, the listener can access the variables button and savedInstanceState. This is not possible with a separate variable defined outside the function.
None of this means that you must use anonymous inner class. Oracle has an excellent tutorial titled General Information about Writing Event Listeners that you will greatly benefit from.
Not exactly. The set-listener requires an instance of listener, so you always need to create one. And I don't think it's a good manner for activity implementing listener interfaces.
The workaround is that you can use annotations with reflection, such as http://code.google.com/p/roboguice/. This may make the code cleaner, but also introduces dependencies.
I am kind of a newbie so excuse me if this question is too simple or too hard.
I have this code in my java file:
public void button_baby_clicked(View v)
{
//do something here
}
this gets called when someone clicks the imagebutton in my xml file, but how do I call this from the java file itself?
Because it's expecting a View object... and I'm guessing I need to recreate that? How?
Edit:
Ok, to clarify, I want to be able to call the above function via a click in my xml file as well as a function under it.
For example:
public void button_baby_clicked(View v)
{
//do something here
}
public void someFunction()
{
x = 10;
button_baby_clicked(); // This should call the above function.
}
In ur ImageButton you have to add an attribute: android:onClick="button_baby_clicked"
In the java file, you have added:
public void button_baby_clicked(View v)
{
//do something here
}
The logic behind this is:
Upon clicking ur imagebutton, this method will automatically get called, i.e "v" argument will be having ur imagebutton.
The advantage of giving like this is: You no need to initialize the imagebutton in ur activity and no need to set click listener too for this imagebutton.
Alright, if you want to have the method invoked every time the view is clicked, do what the others have said.
Alternatively, you can do something like this.
ImageView globalReference;
#Override
public void onCreate(Bundle icicle){
*** CODE ***
globalReference = (ImageView) findViewById(R.id.myImageView);
*** CODE ***
}
Then, whenever you want that to be called with that particular View, simply call
button_baby_clicked(globalReference);
You can also do this with any View object you create dynamically.
View myTv = new TextView(context);
View myLl = new LinearLayout(context);
button_baby_clicked(myTv);
button_baby_clicked(myLl);
Just get a valid View reference within the same scope as the method, and pass it in like any other method. It can even be null if the method is capable of handling it.
Can't you use it like -
mButton.setOnClickListener(new OnClickListener{
#Override
public void onClick(View v) {
button_baby_clicked(v);
}
}
);
??
EDIT :
If you need to call someFunction() from the onClick of a button,and from there,you need to call button_baby_clicked(),you have to get View v object in someFunction. This link might help you. Please refer Start a service on onClick. You can change appropriately.
I believe its best if you refactor your code and put the code in the event handler into a global method that can be called from anywhere. like this:
public void button_baby_clicked(View v)
{
taskToPerform(); // Perform a certain task
}
public void someFunction()
{
x = 10;
taskToPerform(), // Perform the same task again
}
public void taskToPerform()
{
//This is where you write the task you want to perform
}
This way you can reuse the code in the taskToPerform() method anywhere, anytime.
I have a custom class that I've written that extends ImageView (for Android Java). I want to add a ClickListener to every instance I create of the class that will do the same thing (just animate the ImageView.
I tried a few different things to no avail. The code below is what I want to accomplish but it's being applied to an instantiated object of the class.
MyCustomImageView fd = new MyCustomImageView(this);
fd.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
Animater(fd);
}
});
I tried using "implements onClickListener" on the class declaration and then a public void onClick() method in the class, and that didn't work for me.
I also tried using the code snippet above with a "this" instead of "fd" and that didn't work either.
I'm relatively new to java and this is out of the scope of my knowledge. Any assistance you can provide is greatly appreciated.
It's really easy. You have to do it in your custom class:
public class MyCustomImageView extends ImageView{
public MyCustomImageView(Context context){
super(context);
setOnClickListener(theCommonListener);
}
private OnClickListener theCommonListener = new OnClickListener(){
public void onClick(View v) {
// do what you want here
}
}
}
There are other ways to do it, but this is one is really easy to implement and understand. Every instance of MyCustomImageView will have the same event listener (unless you override it from outside).