I am making a module to include with all my applications. In this module, onCreate is overridden to perform code I like doing in all my apps, like using SupportActionBar. In all my applications, I have stuck to keeping my toolbar element id toolbar. I want the overridden function to access this, without actually giving it the id. I don't want to have to do super.onCreate(savedInstanceState, R.id.toolbar) but super.onCreate(savedInstanceState, R.class) or related, and get the function to get the variable on its own, like:
// In custom parent class
protected void onCreate(Bundle savedInstanceState, Class r) {
super.onCreate(savedInstanceState);
Toolbar t = findViewById(r.getClass("id").getInt("toolbar"));
setSupportActionBar(t);
}
// Main func
// Extends class in which above function resides
#Override
protected void onCreate(Bundle b) {
super.onCreate(b, R.class);
}
In parameter should be object of Resources class. So:
// In custom parent class ( extends android.support.v7.app.AppCompatActivity )
public void doStuff(Resources r) {
Toolbar t = findViewById(r.getClass("id").getInt("toolbar"))
setSupportActionBar(t);
}
// Main func
// Extends class in which above function resides
#Override
protected void onCreate(Bundle b) {
super.onCreate(b);
doStuff(getResources()); //we have Resources
}
but i do not undestand what is purpose of sending R as method parameter. It can be done this way:
// In custom parent class
public void doStuff() {
Toolbar t = findViewById(getResources().getClass("id").getInt("toolbar"))
setSupportActionBar(t);
}
// Main func
// Extends class in which above function resides
#Override
protected void onCreate(Bundle b) {
super.onCreate(b);
doStuff();
}
Related
I've created a reusable xml layout that looks like this
I would like to use same component on different activities , what i want to do is to create BaseActivityClass that extends Activity.
public class BaseActivityClass extends Activity {
int layout_id = R.layout.SomeLayout;
final int menu_button_id = R.id.menuButton;
final int save_button_id = R.id.saveButton;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layout_id);
Button btn = findViewById(menu_button_id);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//this functionality will be same on every child class
}
});
}
}
I would like to extend that class as
public class SomeActivityClass extends BaseActivityClass {
int layout_id = R.layout.SomeOtherLayout;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
There is no constructor class for Activity.On intent call only class name is referenced.
And subclass cannot change super class variables(hiding).
I dont want to copy paste same code that is in BaseActivityClass into other classes.
A wrapper class might solve the problem but that seems too sloppy imo.
How can i solve this design issue?
I am free to comment on any idea
Sounds like you want the base class to control the main container layout and allow the derived class to provide a "content" layout. Is that correct? If so, you can use this pattern:
Step 1 - Add a ViewStub to your base layout. Some pseudocode to give you the idea:
<ConstraintLayout>
<!-- Common Stuff -->
<Button id="menu">
<Button id="save">
<!-- "Content" area to be filled by derived classes -->
<ViewStub id="viewStub" />
</ConstraintLayout>
Step 2 - Update your base layout to provide a way to inflate content into the "content area". Some Pseudocode:
public abstract class BaseActivityClass extends Activity {
int layout_id = R.layout.SomeLayout;
final int menu_button_id = R.id.menuButton;
final int save_button_id = R.id.saveButton;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layout_id);
Button btn = findViewById(menu_button_id);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//this functionality will be same on every child class
}
});
// Get the ViewStub, set the derived class's content layout on it and inflate it,
// thereby displaying the derived class's view layout within the base class's
// "content area"
ViewStub vs = findViewById(viewStub);
vs.setLayout(getContentLayoutId());
vs.inflate();
}
// Define abstract method that all derived classes must implement to provide
// the id of the layout to show in the "content area"
#LayoutRes
public abstract int getContentLayoutId();
}
Step 3 - Update your derived class to provide the layout you want to display. Some pseudocode:
public class SomeActivityClass extends BaseActivityClass {
int layout_id = R.layout.SomeOtherLayout;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
#LayoutRes
public int getContentLayoutId() { return layout_id; }
}
Now when SomeActivityClass is created, it calls the super class onCreate which inflates your base layout and then asks the derived class for it's main content layout that it shoves into the "content area".
I've used this pattern on my projects and it works quite well.
Another option is to simply pass the layout ID via the super class constructor. If the base Activity is abstract it will never be instantiated and doesn't have to adhere to the zero-arg constructor rule. Only your derived class does. So you can do something like this:
public abstract class BaseActivityClass extends Activity {
private final int mContentLayoutId;
protected BaseActivityClass(int contentLayoutId) {
mContentLayoutId = contentLayoutId;
}
protected void onCreate(Bundle state) {
// Same code to load ViewStub, but use mContentLayoutId instead
}
}
public SomeOtherActivity extends BaseActivity {
public SomeOtherActivity() {
super(R.layout.SomeOtherLayout); // Call super with derived layout
}
}
Hope that helps!
I have an Activity that has two objects of different classes.
I have a CanvasLayout class that needs to change the activity's objects upon certain conditions.
How do I do this?
CurrentlyCountingActivity
public class CurrentlyCountingActivity extends AppCompatActivity {
CanvasLayout canvasLayout;
//I want to call one of the carCommands and
//pathCoordinates functions from canvasLayout
CarCommands carCommands;
PathCoordinates pathCoordinates;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
canvasLayout = new CanvasLayout(this);
setContentView(canvasLayout);
carCommands = new CarCommands();
//because I don't want the car to be moving initially
carCommands.setAbsoluteSpeed(0, 0);
}
//Other functions dealing with Path coordinates
}
CanvasLayout class
public class CanvasLayout extends SurfaceView implements Runnable {
... initializations here
#Override
public void run() {
prepBrush();
while(canDraw) {
..other irrelevant code
motionPoint();
...more code
if((pointX == INITIAL_X) && (pointY == INITIAL_Y)) {
canDraw = false;
//I would like to have something like
//carCommands.setAbsoluteSpeed(0, 0); here
}
}
}
private void motionPoint() {
//I want to call pathCoordinates of Activity in CanvasLayout
pathCoordinates.trackPathCoordinates();
pointX = pathCoordinates.getX();
pointY = pathCoordinates.getY();
}
}
Use Interface.
SurfaceView
private OnCanvasListener onCanvasListener;
public class CanvasLayout extends SurfaceView implements Runnable {
public interface OnCanvasListener{
public void doSomething();
}
public CanvasLayout(Context this){
onCanvasListener = (OnCanvasListener)this;
}
#Override
public void run() {
prepBrush();
while(canDraw) {
..other irrelevant code
motionPoint();
...more code
if((pointX == INITIAL_X) && (pointY == INITIAL_Y)) {
canDraw = false;
//I would like to have something like
//carCommands.setAbsoluteSpeed(0, 0); here
onCanvasListener.doSomething(); // invoke interface method
}
}
}
}
Implement interface in activity
public class CurrentlyCountingActivity extends AppCompatActivity implements OnCanvasListener {
CanvasLayout canvasLayout;
//I want to call one of the carCommands and
//pathCoordinates functions from canvasLayout
CarCommands carCommands;
PathCoordinates pathCoordinates;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
canvasLayout = new CanvasLayout(this);
setContentView(canvasLayout);
carCommands = new CarCommands();
//because I don't want the car to be moving initially
carCommands.setAbsoluteSpeed(0, 0);
}
//Other functions dealing with Path coordinates
#Override
public void doSomething(){
// implement your logic here.
}
}
Sorry for any typo . hope this will help.
There are several ways to provide access to the CarCommands object:
Create a constructor in CanvasLayout which takes a CarCommands object.
Create a setter method in CanvasLayout which takes a CarCommands object.
Create the CarCommands object in CanvasLayout.
Add methods to the activity class which allow access to the CarCommands object and add a constructor to CanvasLayout that accepts a CurrentlyCountingActivity.
I am sure there are other options as well. Which one you choose depends heavily on other factors in the design of your code. I learn towards #3. Does the activity really need the CarCommands?
I suggest that you continue to learn about object oriented principles. Only experience will help you judge the tradeoffs for design decisions such as this.
My ParentActivity.java is like this
public class ParentActivity extends Activity{
public void childOnlyMethod(){
Log.d(TAG,"child only method triggered in parent activity");
}
public void startChildActivtityButton(){
startActivity(new Intent(this, ChildActivity.class));
}
public void childOnlyMethodButton(){
childOnlyMethod();
}
}
And my ChildActivity.java is like this
public class ChildActivity extends ParentActivity{
#Override
public void childOnlyMethod(){
Log.d(TAG,"child only method triggered in child activity");
}
}
The problem is when I press childOnlyMethodButton, childOnlyMethod() in both parent and child activity gets invoked I want it to be invoked on child only how can I achieve that?
#Override annotation does nothing, it is only used to tell the compiler and IDE that this method overrides its super class. Non-static methods are associated to objects, not classes. Overriding means completely replace the method in its super class. So if you invoke childOnlyMethod on ChildActivity, only child version will be invoked.
I'm guessing you were actually clicking on the parent activity instance. I don't really get the point why you want to invoke a child method on parent reference. If you can post the real code, I can give you more precise answer.
However, you can try the following code. This example will only invoke child version childOnlyMethod on ChildActivity instance. But it will still invoke parent's childOnlyMethod if you click the button on ParentActivity.
public class ParentActivity extends Activity implements View.OnClickListener {
private static final String TAG = "ParentActivity";
private Button mStartChileButton;
private Button mButton;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mStartChileButton = (Button) findViewById(R.id.startChileButton);
mButton = (Button) findViewById(R.id.button);
mStartChileButton.setOnClickListener(this);
mButton.setOnClickListener(this);
}
public void onClick(View v) {
switch(v.getId()) {
case R.id.R.id.startChileButton:
startActivity(new Intent(this, ChildActivity.class));
break;
case R.id.R.id.button:
default:
childOnlyMethod();
break;
}
}
public void childOnlyMethod() {
Log.d(TAG, "Called from ParentActivity");
}
}
public class ChildActivity extends ParentActivity {
private static final String TAG = "ChildActivity";
#Override
public void childOnlyMethod() {
Log.d(TAG, "Called from ChildActivity");
}
}
If you are extending a parent class, all the methods in the parent class are passed down somewhat to the child class, if you don't want the method in the parent class to be implemented, first start by removing that #Override annotation in the child class above the method. Then use this snipped below, all it does is make the Method in the parent class either private or protected so that it can't be accessed in the child class.
public class ParentActivity extends Activity {
private void childOnlyMethod(){
Log.d(TAG,"child only method triggered in parent activity");
}
//OR
protected void childOnlyMethod(){
Log.d(TAG,"child only method triggered in parent activity");
}
}
i cannot access my view script through my activity. what i want to do it:
Activity:
protected void callViewScriptFunction()
{
GameView.somefunction();
}
GameView:
protected void somefunction();
{
// do something
}
You have to first create an instance of GameView to access it:
GameView myView = new GameView();
myView.somefunction();
or you can make a static method in GameView
protected static void somefunction(){
//do something
}
then access it anywhere statically GameView.somefunction()
I am at baby step level of programming on Android (and in Java in general). I do understand that Activity inherits from the Context class. However in every code snippet I have come across, every time a context must be mentionned, it is set to "this".
My question is : when is a context different from "this" ? Could you provide an real life example of context needing to be different from "this"?
Thank you very much.
Typically, you will want to use this when you are "inside" of an Activity. However, when you are using for example a Helper class, the reference this will not work. An example can be something like this:
public class MyActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
}
A case, where you cannot:
public class MyHelper
{
/* some code of yours */
public void lockOrientation(Activity activity)
{
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
}
The above code locks the orientation to the current orientation. Notice that you need to supply the method with an Activity parameter, since you cannot use:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
In the first example, you could use this to achieve this, because you were "inside" of an Activity.
Another type of example, how do you set onClickListener.
First example, when you use this:
public class MyActivity extends Activity implements View.OnClickListener
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Button btn=(Button)findViewById(R.id.mybutton);
btn.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
//handle the click event
}
}
In this example, you can use this because in the first line, we wrote implements View.OnClickListener, so the class inherits from the given interface. Without the implements thingie, you couldn't do it. An example of setting the onClickListener without this:
public class MyActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Button btn=(Button)findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
//handle the click event
}
});
}
}
In the second example, we are defining an Anonymous Inner Class, which will handle the click event of the button. Notice that in this case, our Activity does NOT implements View.OnClickListener.
In Outer Class you directly use "this" reference
In Inner Class Or Abstract Class implementation Or Interface implementation use "classname.this" reference
Example:
class Example{
int number = 0;
public Example(int number){
this.number = number;
}
}
notice that number in the contructor and number in the class are not the same. Altough they have the same name. Saying number = number doesn't make sense. Be using this you can asses number in the class.
For example when you are implementing an OnClickListener the "this" is different.
this is a reference to the current object — the object whose method or constructor is being called.
Inside an Activity's method this can be used as a Context object because Activity inherits from ContextThemeWrapper, which inherits from ContextWrapper, which inherits from Context.
A Fragment on the other hand does not inherit from Context. So to get the Context inside a Fragment you would have to call getActivity() for example.
This applies to any object you are calling this from.
Consider you are inside the OnClick() method of a View.OnClickListener and you want to start an Activity:
button.setOnClickListener (new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(this, NextActivity.class); // wrong because 'this' is the OnClickListener object
Intent intent = new Intent(CurrentActivity.this, NextActivity.class); // correct because 'this' is the CurrentActivity object
startActivity(intent);
}
});