I'm learning android development from Udacity course created by google, in an exercise, it is asked to create a score record for two teams playing basketball. the app looks like :
.
You can guess what each button does ....
To do that they create 6 methods (addThreePointToTeamA, addTwoPointToTeamA...) for each button. but I think that two methods (addTeamA, addTeamB) are enough if I could pass an int parameter correspond to the number of points to add to each method .
So I wonder if it is possible to do that ? and if not, why ?
Thank you in advance
EDIT
here is what I wish to do :
in the layout.xml :
<Button
...
android:text="+3 POINTS"
android:onClick="addThreeTeamA(3)"
/>
then in the MainActivity.java:
public void addThreeTeamA(int point){
....
}
It is technically possible to implement just only one Click Listener but not in the way you asked for since there is no a way to pass parameter to a click listener. Instead, you need to define android:id for every single button and use this approach.
public void buttonClicked(View v) {
switch (v.getId()) {
case R.id.btnAddTeamAThree:
// Add 3 points to Team A
break;
case R.id.btnAddTeamATwo:
// Add 2 points to Team A
break;
case R.id.btnAddTeamBThree:
// Add 3 points to Team B
break;
case R.id.btnAddTeamBTwo:
// Add 2 points to Team B
break;
...
}
}
The answer is simple you can definitely do that.
I would say, think about your design though.
Here is what I would Recommend:
// Setup an interface for common team behaviors
interface Team {
void addPoints(int points);
int getPoints();
}
// implement that interface per Team
class TeamA implements Team {
private int points;
public TeamA(){
this.points = 0;
}
#Override
public void addPoints(int points){
this.points += points;
}
#Override
public int getPoints(){
return this.points;
}
}
And do the same for TeamB!
then create a method in your Activity or whatever class your calling to add from:
public void addPoints(int points, Team team){
team.addPoints(points);
}
Good Luck and Happy Coding!
They created 6 methods for your better understanding. Once you get what they want to perform than you can enhance it. Yes you can enhance it by making generic methods for team-A and team-B. Its totally depend on your logic. Hope i answer your question.
Related
Clean Architecture Question
I have many form activities that has 1 common data that must be appended during submission, my question is, where will the logic must be placed?
Domain or Presentation Layer?
For Presentation:
I'll create a BaseFormActivity that has a method of inserting the needed data on a form that is child of BaseForm which contains the needed data globally.
BaseForm: (to be extended by all forms)
public class BaseForm {
private String globalData;
//getter setters...
}
BaseFormPresenter:
public class BaseFormPresenter extends BaseFormMvpView {
private final GetGlobalDataInteractor mGetData; //to be injected, this is a use case
public void getGlobalData() {
mGetData.execute()
.subscribe(data -> {
getMvpView().showGlobalData(data);
}); //just for the sake of simplicity
}
}
BaseFormActivity: (which is extended by all activity that handles form)
public abstract class BaseFormActivity implements BaseFormMvpView {
#Inject
BaseFormPresenter mPresenter;
//onCreate(), etc
}
SpecificFormActivity: (extends BaseFormActivity)
public class SpecificFormActivity extends BaseFormActivity {
private SpecificForm mForm; //extends BaseForm
//onCreate(), etc
#Override
public void showGlobalData(String data) {
mForm.setGlobalData(data);
}
//then ill just call the presenter to get the global data before submitting
}
For Domain:
SubmitSpecificFormInteractor: (Sorry for the coding, it is just a representation on what I'm thinking to do)
public class SubmitSpecificFormInteractor extends SingleUseCase<Return, Param> {
//to be injected
GlobalRepository mGlobalRepository;
SpecificFormRepository mFormRepository;
//some initialization
public Single<SomeResponse> buildObservable(#NonNull String specificFormData, String anotherSpecificFormData) {
return mGlobalRepository.getGlobalData()
.map(globalData -> SpecificFormDto.create(
specificFormData, anotherSpecificFormData, globalData)) //create the dto then append global data
.flatMap(specificFormDto -> mFormRepository.submit(specificFormDto)) //then submit data
}
}
I'm thinking of placing it on the domain layer (you can see that it is much isolated, but I'll have to do it on all form submissions, which is redundancy), but still I just want to make my decision solid. Refactoring is time consuming. Hope you understand my point here, specially on my pseudocode-like coding. Feel free to comment if there's something hard to understand. Thank you.
In Clean Architecture all business rules go to use case interactors. The main goal is to keep the business rules independent from any details - from any framework - that includes android as well.
The Clean Architecture then uses "interface adapters" (in UI part called "controllers" and "presenters") to map between data most convenient for the inner circles and data convenient for the frameworks.
So in ur case u should go for ur second proposal - even if that means that u have to call the interactor from multiple places and have to map some data types. it is worth the benefits (business rules free from details).
For a more detailed discussion about use case interactors, controllers and presenters pls refer to my posts here: https://plainionist.github.io/Implementing-Clean-Architecture-UseCases/
and here https://plainionist.github.io/Implementing-Clean-Architecture-Controller-Presenter/
i am new and learning , i have checked many related posts but still my few following questions are unanswered...[Edited ]the language is java...
following is the way to handle the click on button but can any one explain
1, why i have to declare the anonymous class ,
2, how i know that i have to declare the anonymous class here or any where else could ?
3, why i cannot use simple the btn.setOnClickListener(); why i must have to call anonymous class here ... below line is simple to do the task ...!!
btn.setOnClickListener();
why to make two more lines of code ...? i.e
#override public void onClick (View v) {....}
======================
Button btnCount = (Button) findViewById(R.id.btnCountId);
btnCount.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) { ...... }
});
You are using a Java entity called an "interface".
View.setOnClickListener accepts an object of type "OnClickListener". So you first need to create an object of such a type.
The Object OnClickListener is indeed an interface with one function "onClick", so to create an object of that type you need to implement it (define all the functions in the interface) - in this case, only one.
OnClickListener myClickListener=new OnClickListener() {
#Override // override means you are implementing a function in the interface or a derived class
public void OnClick(View v) {
// the button has been pressed
}
};
and then you can assign it to a view:
myButton.setOnClickListener(myClickListener);
or to many views:
myButton1.setOnClickListener(myClickListener);
myButton2.setOnClickListener(myClickListener);
myButton3.setOnClickListener(myClickListener);
In Java you'll find objects use listener interfaces to communicate events.
Mind that more complex objects use interfaces that can have several methods instead of just one, that's when the simplification you see is not that handy.
Imagine an object "Girl" that has a method "flirt" that you can invoke to ask her for dinner. The Girl will take some time to decide, then communicate one of a lot possible answers with the same interface.
OnGirlFlirtListener myGirlFlirtListener=new OnGirlFlirtListener() {
#Override
public void onGirlSaidYes() {
// invite the girl to have dinner
}
#Override
public void onGirlSaidNo() {
// find another girl or hang with your mates instead
}
#Override
public void onGirlSaidMaybe() {
// ask her later
}
#Override
public void onParentsHateMe() {
// forget about that girl
}
}
Then you can do:
mGirl.flirt (myGirlFlirtListener);
And the code is indeed elegant: With one interface you control all the possible answers! It's the same for a lot of objects in java (and Android).
Instead of creating the listener as an object, and setting it, you can as well create it as an anonymous class if you won't reuse it, of course.
EDIT
How to create a generic clicklistener?
Sometimes, in the same dialog, you have 15 or 20 buttons that do more or less the same, and only differ in a detail. Although you can perfectly crete 20 clicklisteners, there's a cooler way taking advantage of View.setTag() function.
setTag allows you to store whatever object you want to any view. You use that do distinguish, inside a clicklistener, which button was pressed.
So imagine you have 5 buttons: Brian, Peter, Loise, Krasty and Sue:
mButtonPeter.setTag("Peter Griffin");
mButtonLouise.setTag("Louise Griffin");
mButtonBrian.setTag("Brian");
mButtonKrasty.setTag("Krasty");
mButtonSue.setTag("Sue");
OnClickListener personClickListener=new OnClickListener() {
#Override
public void OnClick(View buttonPressed) {
String person=(String)(buttonPressed.getTag());
// you pressed button "person"
Toast.makeText(buttonPressed.getContext(), "Hey, "+person+", how is it going!!", Toast.LENGTH_SHORT).show();
}
};
mButtonPeter.setOnClickListener(personClickListener);
mButtonLouise.setOnClickListener(personClickListener);
mButtonBrian.setOnClickListener(personClickListener);
mButtonKrasty.setOnClickListener(personClickListener);
mButtonSue.setOnClickListener(personClickListener);
Isn't it cool?
When you are "setting an onClickListener" what you are doing is telling: "when this button is clicked, execute this code".
The code to be executed is implemented in the provided annonymous function.
You can't simply do btn.setOnClickListener() without an argument because that would not provide the information regarding which behaviour to perform when the button is clicked.
I'm using onBackPressed() method in my app in few places.
In every place I want this method to do other stuff.
When user is in X layout I want to Back button does somethink else than in Y layout, so I'm thinking that the best solution would be to use arguments in onBackPressed method.
For example in X onBackPressed(0); and in Y onBackPressed(1); etc.
#Override
public void onBackPressed(int c){
if(c==0)Toast.makeText(getApplicationContext(), "This is X", Toast.LENGTH_SHORT).show();
if (c==1)Toast.makeText(getApplicationContext(), "This is Y", Toast.LENGTH_SHORT).show();
}
But it does not work.
Do You have any ideas what can I do to make it work ? Or is there any better solution for this problem?
you are overriding a framework method and you can't pass it any other parameters than those defined by the API. However you can create an own method to check what you need like:
#Override
public void onBackPressed(){
switch(checkLayout()){
case 1: //do stuff
break;
case 2: .....
}
}
And to extend CommonsWare's comment a little: yes, users are not "in a certain layout". Users are interacting with a certain Activity that is hosting a certain layout. If you don't really understand what this means, you should probably consult this document: http://developer.android.com/reference/android/app/Activity.html
The way overriding methods in Android works is that you must exactly duplicate the method header. When you change it, it will still compile, but Java will read it as an overloaded method and thus not do anything with it because it is never called.
You would be a lot better off handling an instance variable outside of onBackPressed() and then handling it when it's actually pressed.
The following is a simple implementation.
//Your instance variable
boolean myRandomInstanceVariable = true;
#Override
public void onBackPressed()
{
if(myRandomInstanceVariable)
{
//do stuff
}
else
{
//do other stuff
}
}
Create a field in your class set it to some value in some place to some other value in some other place. Then in onBackPressed() check that field's value and proceed accordingly.
I'm a total beginner in coding for Android and java in general and so far in various tutorials I found two ways of handling buttons being clicked.
The first one:
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//do your thing
}
});
The second one involves putting android:onClick="someMethod" in a button's properties in the main.xml and then simply creating the method someMethod in the activity.
I was wondering what is the difference in those two approaches. Is one better than another? Or do they work only subtly differently? To me they seem to do the same :P
Thank!
I was wondering what is the difference in those two approaches. Is one
better than another?
The result is same. But difference is in readability of code.
android:onClick="someMethod"
this approach i don't recommend to you.
I recommend to you use anonymous classes like you meant above.
Also your class can implement for example View.OnClickListener and then you only have to implement onClick() method and you can have one method for many widgets.
public class Main extends Activity implements View.OnClickListener {
public void onClick(View view) {
switch(view.getId()) {
case R.id.startBtn:
// do some work
break;
case R.id.anotherWidgetId:
// do some work
break;
}
}
}
I think this is also good practice, you have only one method and code have less lines and is cleaner.
In first one: You are defining a method pragmatically, that will be called at every press of the button.
In Second one: you are mentioning method name of the activity that will called when button will be pressed.
It totally depends upon your preference which way you like to set a click listener.
Personally, I like to set click listener pragmatically, so that I know which code will execute at onClick of a Button, while going through code.
When you use android:onClick="someMethod", the method is on the activity that holds the clicked view. If you're using this on a list item, it'll be more convenient (in some cases) to have the click handled on the activity.
If you'll use the anonymous class approach, you'll need to set it on the adapter, which not always have access to the activity (and if so - it could get messy..). So if you need stuff from the activity that's holding you list (holding that clickable item) - I think it'll be cleaner to use the android:onClick approach.
Besides that - it's pretty much the same. Be sure to document the methods you call with android:onClick, since it's sometimes hard to track their source later.
To handle double click on android button
// These variables as global
private final static long DOUBLE_CLICK_INTERVAL=250;
private static boolean doubleClick=false;
private static long lastClickTime=0;
private static Handler handler;
// In button method
long clickTime=SystemClock.uptimeMillis();
if(clickTime-lastClickTime <= DOUBLE_CLICK_INTERVAL) { // If double click...
Toast.makeText(getApplicationContext(), "Double Click Event",Toast.LENGTH_SHORT).show();
doubleClick=true;
} else { // If not double click....
doubleClick=false;
handler=new Handler();
handler.postDelayed(new Runnable(){
#Override
public void run(){
if(!doubleClick){
Toast.makeText(getApplicationContext(),"Single Click Event",Toast.LENGTH_SHORT).show();
}
}
}, DOUBLE_CLICK_INTERVAL);
}
lastClickTime=clickTime;
In an effort to reduce duplication, I have my app's workspace split into 3 projects:
Main (A library project, where all of the common code lives)
Free (To make the free version)
Paid (To make the paid version)
Behavior in the free version and the paid version must differ sometimes. How can I "call into" the final projects from the library project?
Here is some sample psuedo-code to illustrate my question:
In the Main project:
private void makeADecision() {
if (AppCode.isPaid()) {
// do one thing
} else {
// do something else
}
}
In the Free project:
public class AppCode {
public static bool isPaid() {
return false;
}
}
In the Paid project:
public class AppCode {
public static bool isPaid() {
return true;
}
}
That is basically what I have tried, but it won't compile because the Main project doesn't know about the AppCode class.
Bear in mind that this is only an example, so try not to focus on how an app can tell if it is the paid version or not. :) So far the best solution I have found is to put a string in the resources of all three projects and then make a decision based on its value but I don't like that method. Besides being ugly, I would prefer to keep functionality where it belongs. That way I can prevent "paid-only" functionality from being compiled into the free version at all and I can avoid having to include any "free-only" code in the paid version.
Step #1: Define an interface in the library, so it is available to all three parties, whose methods are whatever operations you want the library to perform on the app
Step #2: Have the app supply an implementation of the interface to the library via some library-supplied API
Step #3: Have the library call methods on the supplied interface as needed
I don't think it's a good idea to call the main App from the library, even if it's possible.
Instead I'd be adding a public static boolean to the library and set it from within your application once it starts for the first time.
public class MyLibrary {
public static boolean IS_PAID = false;
public void makeADecision() {
if(IS_PAID) {
// do one thing
} else {
// do something else
}
}
}
and in your main application you could do something like
com.yourname.yourlib.MyLibrary.IS_PAID = true;
to set it. Since it's not final, you can change it's state at any time. If it's more complicated behavior, you could use a public static listener or callback which you could assign from your full/free app and then call it from your library
You could use reflection to achieve that - take care that it is usually not a very good idea.
For example:
static private boolean isAppPaid;
static {
try {
Class c = Class.forName("your.package.AppCode");
Method m = c.getMethod("isPaid");
isAppPaid = (boolean) m.invoke(null);
}
catch (Exception e) {
isAppPaid = false;
}
}
There probably are mistakes in my code - I have never used Java reflection much.
Edit: I agree with Tseng that making a library invoke application code is debatable at best. (Except if said library is a framework that takes over the client application.)
You could also make the free and paid versions make subclasses of whatever class makeADecision is in and implement the separate behavior that way.
so in main
public class BaseClass {
...
public void makeADecision() {}
...
}
in free
public class FreeClass extends BaseClass {
...
public void makeADecision() {
//free implementation here
}
...
}
in paid
public class PaidClass extends BaseClass {
...
public void makeADecision() {
//paid implementation here
}
...
}
Tseng Solution is an easy and straightforward solution. Thanks for that, it is the one i have used. Also, I fell upon that article which could help you implement the solution :
http://www.firstlightassociates.co.uk/blog/2011/software/android-software/managing-free-and-paid-android-applications-2/
Hope it will help some of you !
Cheers