Access button reference from other class - android

I have somthing like that:
public class A()
{
private Button myButton;
public void setMyButton(Button myButton)
{
this.myButton = myButton;
}
public Button getMyButton()
{
return myButton;
}
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
setMyButton(button);
}
public class B()
{
public void exampleMethod()
{
A aObject = new A();
Button button = aObject.getMyButton();
}
}
Button in class B is always null. I tryied that:
In class A
public Button myButton;
In class B
A aObject = new A();
Button button = aObject.myButton;
but it is not working too.
I am sure that first is button initiate, then geting button reference. I checked that using logs.
I don't know what is going on, becasue "getMyButton" in class A work fine. How can I get reference of button from class A in class B?
What is the best way to do that?

Looks like you are creating new java object of your activity on your own. Please try to get existing object of an created activity; so that you will get activity context and activity properties as well.

The button is always null because its set in onCreate, which is not automatically called. Let me guess, A is supposed to be an Activity subclass, based on the signature, right? In that case you're doing things really wrong.
*You cannot create an Activity via new, it won't be properly initialized.
*Accessing views of an Activity like that is really weird. It makes more sense to pass the view into B, as B is likely owned by A. If the Activity A doesn't own B, you're probably doing something really wrong. Pretty much if you need to do this you've probably misarchitected something.

The way that you are doing will only works in JAVA and not in ANDROID.
Its because of ACTIVITY class. Activity class reference will be created only when its life cycle is created and you cannot pass the UI elements of one activity to Another.
As the button is associated with the 'A' Class in your case and if you want this in Class 'B' you have to start Activity and its life cycle and also setContentView(R.layout.activity_main);
Other way is get the data that you want from any class and publish the value in 'A' class itself. this can be done by startActivityForResult();

Related

Best approach to access an Activity on the inside of a (custom) view/dialog?

I have only one activity in my app. Before I just stored my views and dialogs static in the activity, so I could access them from anywhere. But I know that this is bad practice because it leads to memory leaks.
So I made them non-static, but now I need to have a reference to my activity deep down in my view hierarchy, to access the views and dialogs stored in the activity.
Example:
My MainActivity has a dialog called a and a custom view called b. How can the onClick method of b show the dialog a?
or in code:
public class MainActivity extends Activity {
private CustomDialog a;
private CustomView b;
#Override
protected void onCreate(Bundle savedInstanceState) {
a = new CustomDialog(this);
b = new CustomView(this);
}
}
public class CustomView extends Button implements OnClickListener {
public CustomView(Context context) {
super(context);
setOnClickListener(this);
}
#Override
public void onClick(View view) {
//wants to show dialog a
MainActivity.a.show(); //Not possible -> a is not static
mainActivity.a.show(); //<-- needs a reference of the activity
// but where from?
}
}
MainActivity mainActivity = (MainActivity) getContext(); won't work because getContext() is not always an activity context.
UPDATE:
I posted an answer below!
For some reasons StackOverflow only lets me accept my own answer in two days
I do not know what exactly your view hierarchy looks like.
I picture your problem for example as:
Activity A has a recyclerview R, now every viewholder H in R should be able to trigger some method in A.
In such a scenario it would be feasable to pass a reference of your activity to your recyclerview adapter and then the adapter passes it to the ViewHolder.
Which then uses it in the onClick method of your (viewholder's) view.
Here, you could use the "callback" pattern. There are many posts about this on stackoverflow, e.g. here.
So the implementation steps would be:
define interface
let your activity implement that interface
let your adapter take the interface as a constructor parameter and pass your activity. (in this example: you have to repeat the step with your viewHolder, pass the interface from the adapter)
use this interfaces method in the onClick method -> this will then trigger your activities method
The implementation depends on the actual hierarchy. If your other view is in a fragment, then you could also use a (shared) ViewModel.
According to your picture I was thinking of the callback-pattern approach first.
You could override onClick in MainActivity; there is probably no need to do it in the class definition itself.
public class MainActivity extends Activity {
private CustomDialog a;
private CustomView b;
#Override
protected void onCreate(Bundle savedInstanceState) {
a = new CustomDialog(this);
b = new CustomView(this);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
a.show();
}
});
}
}
This is a very common pattern in android and I don't know what your view hierarchy looks like but it should work in most cases.
I am having trouble understanding why any class extending Button would need to implement View.OnClickListener. It makes much more sense to create listeners in activities or have MainActivity implement OnClickListener.
A few minutes a go there was an answer here that turned out to be correct.
I don't know why the author deleted it, but it had a link to this answer:
private static Activity unwrap(Context context) {
while (!(context instanceof Activity) && context instanceof ContextWrapper) {
context = ((ContextWrapper) context).getBaseContext();
}
return (Activity) context;
}
So everytime you need the activity you just can call Activity activity = unwrap(getContext());.
I don't know if it is really intended to do it that way or if it is a workaround, but it does its job (atleast in my case).

Change text content depending on button clicked within the same class

My problem is exactly like this link but it's not in android.
I have one button on a layout and two buttons on an another one. On my application, ClickScreen activity can be triggered by either FirstCase activity or SecondCase activity.
I tried to make a conditional statement on my ClickScreen for which activity is triggered but couldn't handle it. I don't want to create two more classes to do this since it's not an efficient technique.
private void goTo2ndPage() {
Intent i3 = new Intent(this, ClickScreen.class);
startActivity(i3);
}
public class ClickScreen extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.click_screen);
}
}
As we discussed in comments. It looks like what you really want is to add extra data in your intent so that Started Activity can get it and act accordingly.
Check out this post !

What is the best way to organize android development code?

I know that every situation will be different, but I just wanted see if there was a general recommendation.
Currently, I have my activities (screens) dynamically creating custom button objects and custom edit text objects. Each of these objects have listeners to see if their state has changed. These object classes have all the logic for the screen. The activity's only job is to assign objects to the widgets I created in XML.
Part of me thinks it should be opposite, where the activity contains all the logic for all the widgets on the screen and simply waits for the objects to notify it when the listeners go off.
Which way is more "standard" ?
I use the following way. I have a common EventHandler sub class in every activity or fragment and I add a single instance belonging to activity to each UI item. EventHandler implements OnClickListener, OnChanged.., and so on.
I would also recommend looking at this library, if you are familiar with DI concept:
https://github.com/roboguice/roboguice/
Here is an example of code of mine:
package com.x.y;
public class DashboardActivity extends FragmentActivity {
private EventHandler eventHandler = new EventHandler();
#SomeAnnotationForInit(R.id.some_id)
private Button feedButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dashboard_activity);
initGui();
}
private void initGui() {
feedButton.setOnClickListener(eventHandler);
}
private class EventHandler implements View.OnClickListener {
#Override
public void onClick(View view) {
if(view.equals(...)) {
//TODO:
}
}
}
}

Pass reference of one Activity to another Activity

I know that I can pass some values between Activities using intent.
However, if I want to pass whole Activity to another Activity I think it is not good approach.
Is there another way to do that?
I have Settings Activity in which I am changing some Colors. So after I come back to my Main Activity I would like to apply those colors. To do this, I need access to MainActivity fields after I change Color value, so inside PreferenceActivity. In other words, I want to have access to Main activity fields from PreferenceActivity class. Any ideas?
You should be using a SharedPreference and then accessing that in your main activity. I recommend you reading up at http://developer.android.com/guide/topics/ui/settings.html because it seems like you are implementing your settings activity incorrectly. The part you might be specifically interested in is the "Read Preferences" section. However, I strongly suggest you read through the whole thing and then implement your settings the proper way.
Updated answer with the 3 different ways (that I can think of):
1) Start your preference activity using startActivityForResult(), then in your onActivityResult() access the SharedPreference and make your necessary changes. See here
2) Register a SharedPreferenceChangeListener with your MainActivity, which will be called when any changes happen to your SharedPreference. See here for a detailed discussion. Also see my initial response.
3) In your MainActivity's onResume(), access the SharedPreference and then make your changes there. I do not like this method because you will be cluttering onResume() with more logic and you will also probably have to have a variable that keeps track of the state of the variable you are interested in.
I would personally go with option 2 because the callback was created for this exact purpose.
I think you could pass the value by using method putExtra(name, value).
And after you start new activity you can get the value you pass before by using method getStringExtra(name).
Shared preferences can be used. If you want your changes to be reflected right away add listener. Refer to SharedPreferences.onSharedPreferenceChangeListener. Its an easy way to do.
If you want to lots of changes required in many activity from you change in any one.
And access last modify data from all Activity and modify also.
for example.
Constants.java
public class Constants
{
public static String name;
}
In your MainActivity you have an editText.
MainActivity.java
public class MainActivity extends Activity {
private EditText yourName;
private Button btn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
yourName = (EditText) findViewById(R.id.yourName);
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Constants.name = yourname.getText().toString();
Intent intent = new Intent(getApplicationContext(),Activity2.class);
startActivity(intent);
}
});
}
In your Activity2 you have an TextView and that getting value which you enter in MainActivity.java without pass in Intent.
Activity2.java
public class Activity2 extends Activity {
private TextView yourName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
yourName = (TextView) findViewById(R.id.tv_yourName);
// directly use ferom serializable class
yourname.setText(Constants.name);
}
like that you use many values from all activity and modify from all activity.

Starting an Android Activity from an Listener defined in an external class file

I have an Activity MyActivity with a Button MyButton.
I want to attach a MySpecialOnClickListener to MyButton.
I write MySpecialOnClickListener in an external class file.
public class MySpecialOnClickListener extends ButtonHandler implements OnClickListener {
public OnClickListenerWithSpeech (Context context)
{ super.context = context; }
#Override
public void onClick(View view) { handleClick(view); }
}
and ButtonHandler looks like this
public abstract class ButtonHandler {
protected Context context;
protected void handleClick (View view){
if (view.getid()==R.id.button_B) {
context.startActivity (new Intent(context, ActivityC.class));
}
}
}
I basically want to store all logic for Buttons in the ButtonHandler.
SO...as I said, I have the MySpecialOnClickListener defined in an external class file.
When I click MyButton I get the following fatal error.
Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
So I can't start an activity normally from within a non-Activity. Fair enough.
However, if I change MySpecialOnClickListener to be an inner class in 'MyActivity' it works fine. Remember 'ButtonHandler' is still an external class file. So it (where ActivityC is ultimately started from) doesn't change.
My question (finally) is: can someone explain the logic of why one is allowed and the other isn't. I presume its a scoping thing or something but I'm a bit confused. It seems the code to start the process of starting an activity has to literally be inside another Activity.
EDIT - PROBLEM SOLVED
See below. The location of the class is irrelevant. I just didn't pass in the context properly.
because the ButtonHandler 'context' field isn´t associated with any activity context. So, when you attach the MySpecialOnClickListener instance to a button you create it passing the context parametener, isn´t???
something like this:
MySpecialOnClickListener listener = new MySpecialOnClickListener(MyActivity.this);
aButton.setOnClickListener( listener );
in this way you´re constructing the Button with the correct context...
It's likely that you are not passing the Activity context to MySpecialOnClickListener. Could you show me the difference in the way you invoke the inner-class approach?
Apologies to those of you who tried to answer. It was my fault (and I didn't include the following info initially for people)
When I was passing in the context to the 'MySpecialOnClickListener' I would do:
view.setOnClickListener(new MySpecialOnClickListener(getApplicationContext()));
when I should have done:
view.setOnClickListener(new MySpecialOnClickListener(this));
So getApplicationContext() doesn't seem to get the "correct" context for the app.
Which leads me to my next question as to what getApplicationContext() actually returns :)

Categories

Resources