How to hide public methods within inheritable class - android

I want to hide some methods within inheritable class from users.
For Example:
public class Test extends TextView {
public Test(Context context) {
super.onCreate(context);
}
/* hide this method */
#Override
protected void setText(CharSequence text) {
super.setText(text);
}
}
And then I don't want to see this method within Test class.
How can I do it? Sorry for my English

This sounds like a design problem since hiding it seems a bit dirty as a base class assigned to subclass should still be able to call base class methods.
You could, however, do one of 2 things.
Mark the method as deprecated. Note: deprecated is usually used to tell people to not use the method b/c it will soon be removed but still presently works whereas here it would not work at all (presumably)...
AND throw UnsupportedOperationException in the method so that you / others catch it early if it is called.
/*
* #deprecated Do not call this method.
*/
#Deprecated
#Override
protected void setText(CharSequence text) {
throw new UnsupportedOperationException("not supported");
}
Instead of subclassing consider composition. By this I mean make a class that wraps the desired class and expose only what you want. If you need a common interface between the original class and your wrapper class, create an interface that they both implement and use the interface but instantiate using your new class.

Related

Is it possible to avoid unnecessary injection in parent class?

Given the following example:
class CustomView extends View {
#Inject
SomeObject mObject;
#Override
protected void onFinishInflate() {
super.onFinishInflate();
getApplicationComponent().inject(this);
}
}
class SecondaryCustomView extends CustomView {
#Inject
AnotherObject mAnotherObject;
#Override
protected void onFinishInflate() {
super.onFinishInflate();
getApplicationComponent().inject(this);
}
}
Both custom views may be used on a layout independently. The second is just a bit more specialized than the first one.
As you can see, both have fields to inject and both need to call inject(). The problem is that when SecondaryCustomView calls its inject(), Dagger injects an instance of AnotherObject and an instance of SomeObject. After the call to super.onFinishInflate(), it creates a second instance of SomeObject. This is not a problem per se, but we are at least creating unnecessary objects.
Is there a way to avoid this? Some way to tell Dagger that a child class has been injected, so ignore the parent injection?
As an example, the Component looks like this:
#Component(...)
public interface AppComponent {
void inject(CustomView);
void inject(SecondaryCustomView);
}
There's no way to do this in Dagger, but you can do it yourself.
To agree with and expand on your point in the comments:
yes it is needed. Dagger does not inject the child objects if we use injection on parent only. however it injects the parent objects if it is called from the child.
That's correct, and noted in "A note about covariance": Though inject(Foo) can accept an instance of Foo or any of its subclasses, Dagger's a compile-time framework; inject(Foo) will not be generated to inject the fields belonging to arbitrary subclasses of Foo because, well, that's impossible to know at compile time. This can be a little surprising, particularly if your Component has both inject(Foo) and inject(FooSubclass) as you have for CustomView and SecondaryCustomView here: With names injectCustomView and injectSecondaryCustomView it would be obvious that only the former is callable from within Foo.
Aside from simply setting an injectedAlready boolean field as a flag, one technique is to create an overridable method, which does not call its superclass implementation:
class CustomView extends View {
#Inject
SomeObject mObject;
#Override
protected void onFinishInflate() {
injectMe();
super.onFinishInflate();
}
protected void injectMe() {
getApplicationComponent().inject(this); // inject(CustomView);
}
}
class SecondaryCustomView extends CustomView {
#Inject
AnotherObject mAnotherObject;
#Override
protected void onFinishInflate() {
super.onFinishInflate();
// ...
}
/** Despite looking identical, the JVM can call the more-specific overload here. */
#Override protected void injectMe() {
getApplicationComponent().inject(this); // inject(SecondaryCustomView)
}
}
If you're looking for a similar solution for Activity and Fragment classes, you can use dagger.android; the built-in mechanism there uses the runtime type of the class to dynamically fetch the right AndroidInjector from a Map. However, that solution doesn't support View at the moment, so this is as close as you can get for your specific case.

How do I abstract away dependencies in Android library code?

Here is my scenario.
I have an android activity in which I want to abstract my I/O dependencies. The dependencies are represented by this interface (edited for brevity and simplicity):
public interface ITimeDataServer {
TimeRecord[] get(int userID);
void save(TimeRecord record);
}
What I want is for my activity to be able to call these interface methods, and leave the implementation to be supplied by the calling code. (Pretty standard, I think).
ITimeDataServer myServer;
int myUserID;
void loadRecords() {
TimeRecord[] records = myServer.get(myUserID);
// etc...
}
My difficulty is, how can I ensure that myServer gets set?
This seems like a common problem, but I can't find a clean solution.
My first thought would be that myServer would be passed in through the constructor, but Android activities aren't really instantiated with constructors.
I've come up with several solutions, but they're all icky in some way:
Icky Solution 1
Create a static method to launch the activity class which takes an ITimeDataServer parameter and stores it in a static variable from which the activity can access it:
private static ITimeDataSource theDataSource;
public static void launch(Activity currentActivity, ITimeDataSource dataSource) {
theDataSource = dataSource;
Intent intent = new Intent(currentActivity, MainActivity.class);
currentActivity.startActivity(intent);
}
This is icky because (a) the data source is static and not actually associated with the instance, and (b) a consumer could initiate the activity by the standard activity API rather than this static method, which will cause NullPointerException.
Icky Solution 2
I can create a Provider class which provides a singleton instance of ITimeDataSource, which needs to be initialized by the calling library before use:
public class TimeDataSourceProvider {
private static ITimeDataSource myDataSource = null;
public void initialize(ITimeDataSource dataSource) {
myDataSource = dataSource;
}
public ITimeDataSource get() {
if (myDataSource == null)
throw new NullPointerException("TimeDataSourceProvider.initialize() must be called before .get() can be used.");
else
return myDataSource;
}
}
This seems a little less icky, but it's still a little icky because the activity's dependency is not obvious, and since there may be many paths to launch it, it's highly possible that some of them would forget to call TimeDataSourceProvider.initialize().
Icky solution 3
As a variation on #2, create a static IODependencyProvider class which must be initialized with ALL dependencies on app startup.
public class IODependencyProvider {
static ITimeDataSource myTimeData;
static IScheduleDataSource myScheduleData; // etc
public static void initialize(ITimeDataSource timeData, IScheduleDataSource scheduleData /* etc */) {
myTimeData = timeData;
myScheduleData = scheduleData;
//etc
}
public static ITimeDataSource getTimeData() {
if (myTimeData == null)
throw new NullPointerException("IODependencyProvider.initialize() must be called before the getX() methods can be used.");
else
return myTimeData;
}
// getScheduleData(), etc
}
This seems superior to #1 and #2 since a failure to initialize would be much harder to sneak by, but it also creates interdependencies among the data types that otherwise need not exist.
...and other icky variations on that theme.
The common themes that make these solutions crappy:
the need to use static fields to pass non-serializable information to an activity
the lack of ability to enforce initialization of those static fields (and subsequent haphazardness)
inability to clearly identify an activity's dependencies (due to reliance on statics)
What's a nooby Android developer to do?
As long as these dependencies implement Parcelable correctly, you should be able to add them to your intent, then unparcel them as ITimeDataServer and get the correct class.
I found a nice solution here, in the least-loved answer.
I define the library activity as abstract and with no default constructor, but a constructor that takes an interface, like so:
public abstract class TimeActivity extends AppCompatActivity {
private ITimeDataSource myTimeDataSource;
public TimeActivity(#NonNull ITimeDataSource dataSource) {
myTimeDataSource = dataSource;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time);
// do stuff with myTimeDataSource!
}
}
Then, the calling code can create a concrete subclass with its chosen implementation that does have a parameterless constructor. No static members, easy-peasy!
This allows you to abstract and inject all sorts of crazy behaviours! Woooo!
(Note that the concrete subclass activity needs to be manually added to AndroidManifest.xml, like all activities, or the app will crash when it tries to launch.)

public Interface for Android

I need a little help with my Interface. I think that i doesn't understand them at all.
So i created this interface to notify every classes that implements it when a certain event occurs.
public interface OnColorsChangeListener {
void onColorsChangeListener(ColorsProp colorsProp);
}
My class that hold the interface:
private OnColorsChangeListener mCallback;
... // other code
// the event occurs here so i call:
mCallback.onColorsChangeListener(mProps);
// but of course here i get an NPE becouse this is undefined in this class.. well, with some replies here i'll understand better how to use that for reach my point
The class that implements it:
public class ClassTest implements OnColorsChangeListener {
... // other code
#Override
public void onColorsChangeListener(ColorsProp colorsProp) {
Log.d(TAG, "Color changed! " + colorsProp.color);
}
i put this in 4/5 classes to be notified in the same time for the color change. I'm quite sure the reason is that I didn't understand very well how them works, so can anyone point me to the right direction? Thank you!
Explanation by example:
You have to instantiate your callback, & it has to be an instance of your class
private OnColorsChangeListener mCallback;
mCallback = new ClassTest();
mCallback.onColorsChangeListener(mProps);
However if you want multiple callbacks you will need to use the Observer pattern.
Simple example:
private List<OnColorsChangeListener> mCallbacks = new ArrayList<OnColorsChangeListener>();
mCallbacks.add(new ClassTest());
mCallbacks.add(new OtherClass());
for(OnColorsChangeListener listener : mCallbacks) {
listener.onColorsChangeListener(mProps);
}
Obviously if you have the class, somewhere else you would not new it up, you would use that reference:
mCallbacks.add(mClassTest);
Observer Pattern Wikipedia
An interface is just a way to group together a bunch of related methods. Implementing this interface then requires you to implement all the methods grouped together by the interface.
The Java Tutorials has a good read on the subject:
What is an interface?
Here's a Stackoverflow thread regarding listener interfaces in android:
How to create our own Listener interface in android?
In short, you don't use the interface directly since it only specifies which methods implementing classes are supposed to implement.

Optional callbacks [duplicate]

This question already has answers here:
Optional Methods in Java Interface
(13 answers)
Closed 8 years ago.
I have the interface
public interface UserResponseCallback {
void starting();
void success();
void error(String message);
void finish();
}
Is it possible to make the methods optional?
A non-abstract class must implement every abstract method it inherited from interfaces or parent classes. But you can use that to allow you to implement only certain required parts as long as you can live with the fact that you can no longer implement the interface at will.
You would create an abstract class that implements the optional part of the interface with empty default implementations like
abstract class UserResponseCallbackAdapter implements UserResponseCallback {
#Override
public void starting() { /* nothing */ }
#Override
public void success() { /* nothing */ }
#Override
public void error(String message) { /* nothing */ }
// finish() intentionally left out
}
You can now create subclasses that have to implement just the required parts while they still can implement the optional parts.
class User {
private final UserResponseCallback callback = new UserResponseCallbackAdapter() {
#Override
public void finish() {
// must be implemented because no empty default in adapter
}
#Override
public void starting() {
// can be implemented
}
};
void foo() {
// can be used like every other UserResponseCallback
CallbackManager.register(callback);
}
}
This technique is for example used by AWT event callbacks e.g. MouseAdapter. It starts getting worth the extra effort once you use the callback multiple times since the optional part needs to be implemented only once instead of every time.
Your next option is top split the interface into two. Your conceptional problem is that your interface contains more than it should have, compare Interface Segregation Principle. You could split it either into two or more actually independent interfaces or you could extend a required base interface with optional extra features like
interface UserResponseCallbackBase {
// this is the only required part
void finish();
}
interface UserResponseCallbackFull extends UserResponseCallbackBase {
void starting();
void success();
void error(String message);
void finish();
}
To use that kind of hierarchical callback you would probably add some intelligence to whatever class manages the callbacks and let it check whether or not a callback wants a certain callback based on it's type.
For example like
class CallbackManager {
private List<UserResponseCallbackBase> mCallbacks = new ArrayList<UserResponseCallbackBase>();
public void register(UserResponseCallbackBase callback) {
mCallbacks.add(callback);
}
public void notifyStarting() {
for (UserResponseCallbackBase callback : mCallbacks) {
// check if callback is of the extended type
if (callback instanceof UserResponseCallbackFull) {
((UserResponseCallbackFull)callback).starting();
} // else, client not interested in that type of callback
}
}
}
That way you can freely choose which type of interface you want to implement and the calling code checks whether or not you want to get a callback. I.e. if you register(new UserResponseCallbackFull() {...}) you would be notified about starting(), if you were to register(new UserResponseCallbackBase() {...}) you would not.
This technique is used in Android with ComponentCallbacks2 which you register via Context#registerComponentCallbacks(ComponentCallbacks) - it takes both a "simple" ComponentCallbacks and the extended version and checks what type you gave it.
No, that's not possible in Java.
Have a look at this question that comes to the same conclusion: Optional Methods in Java Interface
No.
Use a dummy implementation and override if needed.

How does exactly custom Shadow objects work in Robolectric?

If I write a custom Shadow for my Activity, and registering it with RobolectricTestRunner, will the framework intercept the Activity with my custom Shadow whenever it's started?
Thanks.
The short answer is no.
Robolectric is selective about what classes it intercepts and instruments. At the time of this writing, the only classes that will be instrumented must have a fully qualified classname match one of these selectors:
android.*
com.google.android.maps.*
org.apache.http.impl.client.DefaultRequestDirector
The whole reason for Robolectric's existence is that the classes provided in the Android SDK jar throw exceptions when invoked in a JVM (i.e. not on an emulator or device). Your application's Activity has source that is not 'hostile' (it probably does not throw exceptions when the methods or constructors are invoked). Robolectric's intended purpose is to allow you to put your application's code under test, which would otherwise not be possible due to the way the SDK is written. Some of the other reasons why Robolectric was created were:
The SDK does not always have methods that would allow you to query the state of the Android objects manipulated by your application's code. Shadows can be written to provide access to this state.
Many of the classes and methods in the Android SDK are final and/or private or protected, making it difficult to create the dependencies needed by your application code that would otherwise be available to your application code.
The code could clearly be changed to shadow any class. There has been talk in the past about extracting the shadowing features into a standalone library, to assist writing tests using some other test-hostile api.
Why do you want to shadow your Activity?
This has significantly changed with Robolectric 2. You can specify custom shadows in the configuration instead of writing your own TestRunner.
For example:
#Config(shadows = {ShadowAudioManager.class, ShadowContextWrapper.class})
Yes, if you subclass the RobolectricTestRunner, add a custom package to the constructor and load your Shadow classes in the bindShadowClasses method. No need to use the android.* package trick.
(Note: this is with robolectric-1.1)
There are a number of hooks provided in the RobolectricTestRunner#setupApplicationState that you can override.
Here's my implementation of the RobolectricTestRunner.
import org.junit.runners.model.InitializationError;
import com.android.testFramework.shadows.ShadowLoggerConfig;
import com.xtremelabs.robolectric.Robolectric;
import com.xtremelabs.robolectric.RobolectricTestRunner;
public class RoboRunner extends RobolectricTestRunner {
public RoboRunner(Class<?> clazz) throws InitializationError {
super(clazz);
addClassOrPackageToInstrument("package.you're.creating.shadows.of");
}
#Override
protected void bindShadowClasses() {
super.bindShadowClasses(); // as you can see below, you really don't need this
Robolectric.bindShadowClass(ShadowClass.class);
}
}
More methods you can subclass (from RobolectricTestRunner.class)
/**
* Override this method to bind your own shadow classes
*/
protected void bindShadowClasses() {
}
/**
* Override this method to reset the state of static members before each test.
*/
protected void resetStaticState() {
}
/**
* Override this method if you want to provide your own implementation of Application.
* <p/>
* This method attempts to instantiate an application instance as specified by the AndroidManifest.xml.
*
* #return An instance of the Application class specified by the ApplicationManifest.xml or an instance of
* Application if not specified.
*/
protected Application createApplication() {
return new ApplicationResolver(robolectricConfig).resolveApplication();
}
Here's where they're called in the Robolectric TestRunner:
public void setupApplicationState(final RobolectricConfig robolectricConfig) {
setupLogging();
ResourceLoader resourceLoader = createResourceLoader(robolectricConfig);
Robolectric.bindDefaultShadowClasses();
bindShadowClasses();
resourceLoader.setLayoutQualifierSearchPath();
Robolectric.resetStaticState();
resetStaticState();
DatabaseConfig.setDatabaseMap(this.databaseMap);//Set static DatabaseMap in DBConfig
Robolectric.application = ShadowApplication.bind(createApplication(), resourceLoader);
}
As an update, I have been able to create shadows of my own classes, as long as am careful to bind the shadow class before any possible loader acts on that class. So, per the instructions, in the RoboRunner I did:
#Override protected void bindShadowClasses() {
Robolectric.bindShadowClass(ShadowLog.class);
Robolectric.bindShadowClass(ShadowFlashPlayerFinder.class);
}
Did I mention that I'm cheating a bit? The original answer above is (of course) correct. So I use this for my real class:
package android.niftyco;
public class FlashPlayerFinder {
.. .
And my mock (shadow) is in back in my test package, as one might expect:
package com.niftyco.android.test;
#Implements(FlashPlayerFinder.class)
public class ShadowFlashPlayerFinder {
#RealObject private FlashPlayerFinder realFPF;
public void __constructor(Context c) {
//note the construction
}
#Implementation
public boolean isFlashInstalled() {
System.out.print("Let's pretend that Flash is installed\n");
return(true);
}
}
Might be late, but from here: org.robolectric.bytecode.Setup, you might find further detail about what classes are instrumented.
public boolean shouldInstrument(ClassInfo classInfo) {
if (classInfo.isInterface() || classInfo.isAnnotation() || classInfo.hasAnnotation(DoNotInstrument.class)) {
return false;
}
// allow explicit control with #Instrument, mostly for tests
return classInfo.hasAnnotation(Instrument.class) || isFromAndroidSdk(classInfo);
}
public boolean isFromAndroidSdk(ClassInfo classInfo) {
String className = classInfo.getName();
return className.startsWith("android.")
|| className.startsWith("libcore.")
|| className.startsWith("dalvik.")
|| className.startsWith("com.android.internal.")
|| className.startsWith("com.google.android.maps.")
|| className.startsWith("com.google.android.gms.")
|| className.startsWith("dalvik.system.")
|| className.startsWith("org.apache.http.impl.client.DefaultRequestDirector");
}

Categories

Resources