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.
Related
So, I am trying to write text to a file in Android Studio. I have the following code:
public void sampleFunction() {
File file = new File(getExternalFilesDir(null), "sample-file.txt");
}
The issue is that the method getExternalFilesDir(null) cannot be resolved. After doing some research I have noted that I need to provide the Context class. Such as:
public void sampleFunction(Context c) {
File file = new File(c.getExternalFilesDir(null), "equation_history.xml");
}
And when I called sampleFunction, I would simply pass in the current Context:
sampleFunction(this);
This normally would work, however, I need to call this function inside a setOnClickListener function for a Button. For example:
Button b_go = findViewById(R.id.b_go);
b_go.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Functions.sampleFunction(this);
}
});
So the return value for this is android.view.View.OnClickListener rather than android.content.Context.
How might I get around this? Any advice would be greatly appreciated.
Instead of passing "this" as an argument try calling getApplicationContext() or if you are in fragment just call getActivity().
What is often done is that a Context myContext variable is declared in the class, then onCreate, you populate it with myContext = this; Then, in any listener or Async Task, you can use myContext.getExternalFilesDir(null)
File storageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
I need some pointers on doing the following:
lets say i have 10/20 (number doesn't matter) of activities.
each of these activities has a textview that should work like a counter.
each of these activities has a button to go to the next activity.
this counter starts when the app is launched, and increment itself every second.
So what i did so far is:
have in my main activity a method that instantiate a class that extends Thread.
In that class in the run() method, i increment a variable when a second passes.
Now i'm stuck on what i should do next. Any pointers would be appreciated thanks.
Edit: i need a way to communicate from inside the run method, to whichever activity is now currently on screen, to update its textview.
Just a bit of theory here for standard Object Oriented Programming : stick to the recommended principles like Loose Coupling which makes your project code less tied to each other. You can read more on that later.
Now, using Events, you can setup a system that is synonymous with the natural Publisher/Subscriber design pattern. Like this:
The activity that needs to notify the other activities is called Publisher and the other activities that need to be notified are called Subscribers.
From here:
There are already built and tested libraries to do Events in android. Like my favorite EventBus.
Step 1 Add this line to your app-level build.gradle file:
compile 'org.greenrobot:eventbus:3.0.0'
Then create a simple Plain Old Java Object aka POJO class like this:
public class UpdateTextViewEvent{
private String textToShow;
public UpdateTextViewEvent(String text){
this.textToShow = text;
}
//add your public getters and setters here
}
Step 2 Notify others:
When you want to notify anyone of the changes, you simply called this method:
EventBus.getDefault().post(new UpdateTextViewEvent("Some new Text"));
Step 3 Receive notifications
For those who want to be notified of this event, simply do this:
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
NOTE: to actually handle the event:
#Subscribe
public void onEvent(UpdateTextViewEvent event){
String text = event.getTextToShow();
//now you can show by setting accordingly on the TextView;
}
This is so much easier to do, do decouple your code by eliminating static references in your different activities
I hope this helps! Good luck!
make that Textview in second class as
public static Textview text;
and call it in main activity as
SecondActivity obj=new SecondActivity();
obj.text.settext("");
You can create one another activity e.g. BaseActivity extend with Activity class and your all 10/20 activity extends with created BaseActivity Class.
You can use your textview with protected access specifiers.
What you need to do is inside the counter class, create an a method and passed in a TextView as the parameter. Then create an int variable and set the counter as the instance:
Like this
public static class Counter extends Thread{
private static int x;
#Override
public void run(){
x = counter;
}
public void setCounter(TextView tv){
tv.setText(String.valueOf(x));
}
}
Now call this method setCounter(TextView) in all the activity's onCreate() method you'll like to display the counter, and passed in your the layout TextView as the argument. Like this
...
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState):
....
TextView cTextView = (TextView)findViewById(R.id.texT1);
Counter c = new Counter();
c.setCounter(cTextView);
}
most of my apps are apps with just one screen (due to the functionality) sometimes being extended by "floating" popups that are basically RelativeLayouts (containing other UI elements) that are being added to the Main layout, keeping the UI Elements of the Main layout active and "touchable" in the background.
For a better understanding, please just look at the sketch (purely symbolic):
If you include all the stuff from the popups as well, I have about 90 UI elements, a dozen of custom View classes like buttons, sliders, ... at a time, all of them needing to have certain listeners running on them, all of them having to be resized on start up [...]
I, in fact, write quite efficient (in terms of amount of bytes used) code, and if there is a 3-line method to return a value that replaces 4 lines of additional code, I write this method just to satisfy myself. However, I quite don't understand how to outsource code from my MainActivity to other classes. Of course, if there is a calculation to be made, this is something that I put into another class rather than just creating a method in my MainActivity class. Anyway, my MainActivity is now at 1600 lines of code which is an awful amount of text to overview for debugging, adding or changing code. The variable declarations of my UI elements alone take 100 lines of code (maybe 70 lines if compressed)
That was the longest explanation I ever made for a post but now we get to my question:
How can/do you outsource code like listeners, UI stuff like findViewById() or similar things to other classes? Are there common practices to do so in an efficient way? I don't want to go for clumsy workarounds that skyrocket the CPU, so "smooth" stuff is stuff I am looking for.
It might be KIND OF off-topic but I hope it's ok to be asked here.
I'm not sure that there is particular answer on your question because I suppose it's all about experience which you can get reading source code of other projects for instance. But I have few advices which could help you:
1. Use libraries which eliminate boilerplate code like findViewById and listeners. One of them is Butterknife
7 lines of code:
View text = findViewById(R.id.text_id);
text.setOnClickListener(
new View.OnClickListener() {
#Override public void onClick(View v) {
//
}
}
);
2 lines code:
#OnClick(R.id.text_id) public void handleClickOnText() {
//
}
2. Use static helper classes:
4 lines of code:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.new_message);
builder.setTitle(R.string.create_calendar_title);
builder.show();
1 line of code:
DialogsHelper.newMessage(this);
3. Read about MVP. It's about modular app architecture. Roughly speaking it helps to divide raw View from logic.
Basic sample:
public static class SomePresenter {
private SomeView view;
public SomePresenter(SomeView view) {
this.view = view;
view.showProgressLoading();
loadData();
}
private void loadData(){
//loading data from some server
}
private void loadingDataHandler(SomeModel model){
view.showData(model);
}
}
public static class SomeView extends View{
#Inject(R.id.text_progress_title) TextView text;
public SomeView(Context context) {
super(context);
ButterKnife.inject(this);
}
public void showData(SomeModel model){
text.setText(model.dataA + ":" + model.dataB);
}
public void showProgressLoading(){
text.setText(R.string.progress);
}
}
public static class SomeModel{
public final int dataA;
public final int dataB;
}
And your onCreate method of activity could look like this:
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
new SomePresenter(someView);
}
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 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).