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.
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 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();
}
I faced a major problem when I need to call another activity when the button is clicked after the Game is started. The Game is called via initiate(game, ) method from AndroidApplication interface.
In normal Activity, I can easily call the another Activity but it seems to be difficult to call another Activity from Libgdx class that implements AndroidApplication.
Could anyone suggest a proper method to call the Activity from Libgdx class that implements AndroidApplication interface?
I tried to do this for a week but it seems that my method is totally wrong..
Thanks in advance.
Define a callback interface in you LibGdx class, and use it to notify your AndroidLauncher to start the new activity.
For example in your LibGdx game class:
// Your Game class in the core package
public class MyGame extends Game {
// Define an interface for your various callbacks to the android launcher
public interface MyGameCallback {
public void onStartActivityA();
public void onStartActivityB();
public void onStartSomeActivity(int someParameter, String someOtherParameter);
}
// Local variable to hold the callback implementation
private MyGameCallback myGameCallback;
// ** Additional **
// Setter for the callback
public void setMyGameCallback(MyGameCallback callback) {
myGameCallback = callback;
}
#Override
public void create () {
...
}
...
private void someMethod() {
...
// check the calling class has actually implemented MyGameCallback
if (myGameCallback != null) {
// initiate which ever callback method you need.
if (someCondition) {
myGameCallback.onStartActivityA();
} else if (someOtherCondition) {
myGameCallback.onStartActivityB();
} else {
myGameCallback.onStartSomeActivity(someInteger, someString);
}
} else {
Log.e("MyGame", "To use this class you must implement MyGameCallback!")
}
}
}
Then ensure your AndroidLauncher implements the required interface:
// Your AndroidLauncher
public class AndroidLauncher extends AndroidApplication implements MyGame.MyGameCallback {
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
// create an instance of MyGame, and set the callback
MyGame myGame = new MyGame;
// Since AndroidLauncher implements MyGame.MyGameCallback, we can just pass 'this' to the callback setter.
myGame.setMyGameCallback(this);
initialize(myGame, config);
}
#Override
public void onStartActivityA() {
Intent intent = new Intent(this, ActivityA.class);
startActivity(intent);
}
#Override
public void onStartActivityB(){
Intent intent = new Intent(this, ActivityB.class);
startActivity(intent);
}
#Override
public void onStartSomeActivity(int someParameter, String someOtherParameter){
Intent intent = new Intent(this, ActivityA.class);
// do whatever you want with the supplied parameters.
if (someParameter == 42) {
intent.putExtra(MY_EXTRA, someOtherParameter);
}
startActivity(intent);
}
}
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);
}
});
New programmer. Questions at the bottom.
I have an array of fleets that corresponds to vehicles. I would like to make successive calls to the server with each slot in my fleet array.
I wish to do this with an AsyncTask.
private class refreshTruckInformation extends AsyncTask<URL, Void, Void> {
#Override
protected void doInBackground(URL... urls) {
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected void onPostExecute(Void... voids) {
}
}
**How do I pass in my array of fleets so that I can use them in my doInBackground?
I also want to have a progress bar that goes based on the percentage of fleets it has gone through. What is a good way to do this?**
Thanks!
**How do I pass in my array of fleets so that I can use them in my doInBackground?
Remember that refreshTruckInformation is still a class. So you can use any constructor or settier methods to pass your array.
I also want to have a progress bar that goes based on the percentage
of fleets it has gone through. What is a good way to do this?**
From your doInBackground method you can publis progress using publishProgress method. This progress parameter will be catched in onProgressUpdate method
For example
private class RefreshTruckInformation extends AsyncTask<URL, Void, Void> {
private int[] b;
public RefreshTruckInformation (int[] a){
// use array
b = a;
}
public void setArray(int[] a){
// use array
b = a;
}
#Override
protected void doInBackground(URL... urls) {
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected void onPostExecute(Void... voids) {
}
}
And call using
RefreshTruckInformation r = new RefreshTruckInformation (yourArray);
or call method like
r.setArray(yourArray);
and execute like
r.execute();