Multiple projects depending on 1 library - android

I'm not sure SO is the right place to ask this question so let me know if I should maybe post it on ProgrammersSE.
I've got an Android library project which comes with some functionality and some basic XML files. In the nearest future I'll be developing multiple apps which will heavily depend on that library - it's possible that some of them will only differ in that they'll be using different XML layout files and image resources. As far as I know Android will automatically pick the ones from the regular projects instead of the library one if the names of the appropriate files are the same so this shouldn't be a problem.
The problem is I expect that some of the projects will have to have a slightly extended functionality - meaning I'd have to, e.g., extend the classes which are in the library project.
I just tried that out but obviously that didn't work as I wasn't overriding the entire code of a class - just adding to it, meaning I seemingly can't have the the library Activities call the classes from my regular project.
Is there any way around that without using reflection?
Is there maybe a better way of handling such a situation?
Edit for clarification:
Thanks to #jucas and #Alex Cohn for the answers and the links. I'm not sure if the solutions you wrote are applicable to my situation - I'd probably have to see examples of those coded to decide if I can do anything similar in my project.
Here's an example of what makes this problematic for me: say in my library project I've got a class called MyActivity which extends Activity and implements OnScrollChangedListener because there's a ScrollView in it whose background has to scale. There could be something like this in it:
#Override
public void onScrollChanged() {
int currentScrollOffsetY = this.scrollView.getScrollY();
// No case for further back than the bottom of the screen (lower than 0)
// and if it's higher than where it should stop, keep it at that point
if (currentScrollOffsetY > this.screenHeightPx * MULTIPLIER_Y_ANIMATION_STOP) {
currentScrollOffsetY = (int) (this.screenHeightPx * MULTIPLIER_Y_ANIMATION_STOP);
}
// Set the pivot points of the background images
this.imageBackground.setPivotX(this.imageBackground.getWidth() / 2.0f);
this.imageBackground.setPivotY(0);
// Scale the background
float newBackgroundScale = 1 - (float) currentScrollOffsetY / (float) this.screenHeightPx;
if (newBackgroundScale < 0.75f) {
newBackgroundScale = 0.75f;
}
this.imageBackground.setScaleX(newBackgroundScale);
this.imageBackground.setScaleY(newBackgroundScale);
}
As you can see, the new scale for the background image is never smaller than 0.75 of the original size. Now if one of the projects using the library project needed that to be 0.8 instead, I could just move the value from the code to the XML values resources and it should be dynamically read from there - that's perfectly fine.
But what if I not only wanted to do that but also scale another ImageView?
this.imageBackground.setScaleX(newBackgroundScale);
this.imageBackground.setScaleY(newBackgroundScale);
this.differentImageBackground.setScaleX(newBackgroundScale);
this.differentImageBackground.setScaleY(newBackgroundScale);
How could this be achieved? I'm sorry if I don't understand this straight away - I've never done anything like this yet and some concepts are a bit difficult for me to get my head around them.

This a very common problem, and one that has several answers that might or might not be the best for your particular case, here are 2 from the top of my mind:
Develop a plugin architecture for your app, to load content and functionality from plugins Plugins architecture for an Android app?, note that this might be overkill if you just need to change a few classes here and there.
Modify your library project's architecture: This is one that I tend to use the most, just because it is simply and doesn't require a very complex refactoring. The steps needed for this are usually like this:
a. Figure out which parts of your activity or fragment might need to be extended by your main app project
b. Create interfaces and classes that implement those interfaces for the extendable functionality
c. This is the tricky part, isolate the creation and use of those classes in specific methods inside your activities or fragments
d. Finally on your main app project, create new classes that implement the same interfaces and override your fragments or activites to create these classes instead
I hope this helps you a bit, and if it doesn't you might want to sketch out some code in order to see exactly what problems you are having

This looks like a good fit for "inversion of control" design pattern. If a ExtendsActivity class is not changed between projects, but sometimes it uses an actor of class MyActor and sometimes ExtendsMyActor, then you should prepare a way for ExtendsActivity to accept the reference to such actor. You can inject this reference on construction, or later during the lifecycle of activity.
It is often recommended to use interface, i.e. define IActor and have both MyActor and any alternative implements this interface. But in some cases, extends fits perfectly, too.

Related

Why are ViewPropertyAnimatorRT missing in API 29?

I want to use this class to render the animation in the word thread,
But now I can't find this class, who can tell me why this class was deleted?
question why it was removed should be answered by someone from Android team. probably they just refactored some internal animation utils due to new possibilities...
you can always copy-paste this class source and paste into your project (with different name just in case), you probably should find workaround for FallbackLUTInterpolator usage (or just remove related items, supplying different Interpolator in this place, eg. linear)
SOURCE

Where to put helper methods?

I have a method that darkens a given hex color and percent. Currently, the only place I use this method is within one of my Activity classes (I may or may not end up using it in other classes later on).
public static int darkenColor(int color, int percent) { ... }
However, where should I put this method? Should I create a new class called Helpers that contains all of these methods that I may use only once throughout the entire app?
This is just a matter of choice. You can have Set of utility classes and have these helper methods to be in those classes. But, This method is for not used in one of your activity, and If you do not see that it will get reused in the near future in some other point, Put it as a private method inside your Activity. I say this because you do not want to over complicate the code and also By this way another developer can easily follow the flow of execution.
But after sometimes if you feel, that this code is getting reused, put that into a logically meaningful Utility class. When the code base is huge, you do not have any choice to follow a solid standardization of there to put your code, That is why there are things like Layered architectures etc.

Activity is getting too large and becoming more and more difficult to work with. Solutions to solve this issue?

I am working on my second Android Application, first being, hello world. The application code is quite crazy looking because I love to test new libraries and ideas in it. I have been working on this application for well over 3 months and one of my activities is getting way to large and difficult to work with. I find myself getting lost in the code and it is taking longer to do simple things. There might be simple solutions to solving this issue. I really want to split my activity into two and reference each other if possible. Is there are any suggestions to simplifying and organizing code that would be greatly helpful. Even example will help me very much.
Part of my activity is adding a ton of data into a database and the other part is a long equation with multiple values. Another part is implementing the HoloGraphLibrary (Which I love). It is also implementing a listView with custom adapter. It also has a custom dialog............ I can go on and on. I hope you get my point.
EDIT
Going to work with this.
HoloGraphHelper holoGraph = new HoloGraphHelper();
holoGraph.initialize();
Try creating classes for each responsibility.
A Database Helper that has functions to insert data too:
DatabaseHelper database = new DatabaseHelper();
database .insertData(whatever);
A HoloGraphHelper that initializes the HoloGraph
HoloGraphHelper holoGraph = new HoloGraphHelper();
holoGraph.initialize();
And so on.
Break into multiple files. First classes defined in the Activity like the adapter. Change anonymous classes to classes defined in their own file. Look for ways to break out other related code into a class.
Right click on src folder of your Project and select new - class to create a new class. You can use a class for storing methods but you won't be able to display anything on screen.
To display contents to user, you can create a new Activity bu pressing Ctrl + N and selecting Android - Android Activity.
The best way is modularise your code.
I.e split your code into various related modules, for example a separate class for each part that your testing. So you could have a database entry class, a class for Gui testing, i.e. for your custom dialog. That class does all the work for that test, into various functions, I always try to keep functions as small as possible as they are easy to read.
As an example for your database entry, you could have a function which checks the database if the record already exists and then insert it. But a better way would be your insert function only performs the insert code and instead within this function it calls CheckIfDatAlreadyExists function which can return a bool so you know whether you should go ahead and insert the record. This would keep the code tidy and clean to manage.
Then from your main activity all would need to do is instantiate the relative class and call the relevant method.

Android Spinner - System view VS User view

I have been creating Spinner controls (Combo boxes/Drop downs) in one of my apps, and was surprised to find out how difficult it was to achieve all of the following features:
User facing Strings are externalized, taking advantage of strings.xml internationalisation (I18N) feature of Android.
Spinner selections operate using a System view, which facilitates not having to work with or map Strings to meaningful values (yuck).
User view to System view mapping should be easy, automated and minimal (i.e not hand rolled for every component).
Others have attempted solutions to this, but universally as far as I could see they suffer from one or many of the following problems:
UI code is creeping into their enum class which doesn’t belong there (messy), nearly all existing solutions suffered from this.
Hardcoded User facing Strings in their enum classes. Because these are not externalized you cannot do I18N using the stock Android features.
Authors typically make the Fragment or Activity an OnItemSelectedListener which perpetuates a common problem of inheritance for convenience, where composition is more appropriate.
I have developed my own solution which does this: http://www.androidanalyse.com/android-spinner-externalize-user-strings-mapped-to-system-enum/
My question is, have I missed something? This seems like something that should not have been this hard (which makes me feel like I'm possibly reinventing the wheel).
Below is some example code showing my solution in-use (which is available Apache 2 license from the link above).
String none = getString(R.string.none);
String light = getString(R.string.light);
String medium = getString(R.string.medium);
String strong = getString(R.string.strong);
SpinnerUtil.createNewSpinner(view, R.id.wind, Arrays.asList(none, light, medium, strong), WindLevel.values(),
new SpinnerItemSelectedListener<WindLevel>() {
public void onItemSelected(Spinner item, WindLevel value) {
// Take whatever action you wish to here.
}});
I would just use ArrayAdapter<WindLevel>. Yes, you created a custom typed listener, but the regular event listener gets the position and can call getItem() on the ArrayAdapter<WindLevel> to get a WindLevel properly typed.
IMHO, the vast majority of Spinner widgets will be populated with material read in from a database, the Internet, or some other dynamic data source, rather than populated by some sort of enum with display values coming from static strings that can be internationalized ahead of time.
This is not to say that your code is useless: if you find it useful, then it was worth writing. And I am sure that there are apps out there that contain your targeted pattern (i.e., a Spinner backed by an enum or equivalent where the display values are known in advance and can be internationalized) who might find your solution useful as well. Every developer who writes enough code cooks up these sorts of helper classes and the like that help map an OS or framework model into something that better fits the developer's own mental model. So long as you are not perceiving any performance issues, it's all good.
Also, note that OnItemSelectedListener is an interface; implementing that interface on an existing class is not inheritance.
I believe the reason nobody answered you is :
What problem are you trying to solve ? Spinners existed prior to your well designed attempt.
Why reinvent them in exactly the same way they exist in Android ?
http://developer.android.com/guide/topics/ui/controls/spinner.html
It is a beautiful wheel indeed you designed, but still, it is just a wheel :)
UPDATE :
I think I begin to understand what you did. This is interesting. I'm not sure why you did not go to the pattern implemented by the ListPreference with its entries and entryvalues.
In fact, I'm not sure I understand why the Android team did not go that route either.
In any case, it is worth proposing your idea to the Android framework. It is after all open source.

Android: How to best pass data to a view?

I have a view that displays all the levels of my game. These levels are read by the activity and then passed into the view. I could read them from the view, but it's not really its responsibility, and I'm a fan of separation of concerns.
Right now, I'm calling a setter for this:
((GameView) findViewById(R.id.game)).setLevels(loadLevels());
However, I don't like the fact that the view will be dysfunctional if I forget to call the setter. Is there a better way to pass the levels in?
It is also a bit a matter of preference. Theoretically it's perfectly fine to pass the levels as you're doing. Alternatively, if you need more than just set the levels, but provide further functionalities (i.e. also saving of levels) I normally use a separate class responsible for handling such things (i.e. a Repository, some "Manager" class etc...). This class is then passed into the View on the constructor preferably s.t. one is forced to provide it. Of course, in order to separate things, I use interfaces rather than specific implementations s.t. it may then look as follows:
public class MyView {
public MyView(ILevelLoader levelLoader){
this.levelLoader = levelLoader;
}
...
}
Often, this may not work, because the view is something instantiated by the framework directly rather than by the application. In such a situation you're forced to do it through an appropriate setter. It is some sort of MVC/MVP pattern.
Just for your interest, you might also want to take a look at IoC containers and dependency injection. Guice provided by Google is a nice framework I've already used on Android.
I hope I didn't miss the point, but here goes:
Generally you have either a function setting something (like the text for a textview), or an attribute you set in the xml.
Take a look over at this answer I got on a question: How to layout a 'grid' of images in the center of the screen
There are some things the custom view needs, but lets take an example: 'numColumns'.
you can set it using setNumColumns (that would be the equivalent of your loadLevels() ? )
you can ignore it, it'll revert to default.
you can set it as an attribute lik so: app:numColumns="3"
You can try to use the attribute or the default in the class to accomplish this.
Make your view an abstract class with an abstract method getLevels()? This way, when you instantiate the class if you forget to pass the levels in your code won't compile.
Whether or not this is better is a matter of taste I guess :)

Categories

Resources