command pattern, why does this not work - java

I am implementing a command pattern in android.
This is what I have right now. For some reason this does not run. It is like the AddUserRequest is getting garbage collected for some reason.
RequestManager.java:
public class RequestManager extends BroadcastReceiver {
private static final RequestManager instance = new RequestManager();
private boolean isConnected = false;
private static ArrayList<Request> requestQueue = new ArrayList<Request>();
private RequestManager() {
}
/* singleton class */
public static RequestManager getInstance() {
return instance;
}
public void invokeRequest(Request request) {
request.execute(); // only to test this, this will change
return;
}
}
AddUserRequest.java
public class AddUserRequest extends InsertionRequest {
User user;
public AddUserRequest(User user) {
this.user = user;
}
public void execute() {
System.out.println("TEST!!!");
}
}
Request.java:
public abstract class Request {
public abstract void execute();
}
}
InsertionRequest.java
public abstract class InsertionRequest extends Request {
}
RequestManagerTest.java
public class RequestManagerTest extends ActivityInstrumentationTestCase2 {
public RequestManagerTest(){
super(MainActivity.class);
}
public void testAddUserRequest() {
User user = new User();
user.setName("Tester12345");
AddUserRequest request = new AddUserRequest(user);
RequestManager.getInstance().invokeRequest(request);
}
}
For some reason this does not print "TEST!!!" and for the life of me I cannot figure out why. I looked in the debug log and everytime request.execute() in RequestManager.java gets called there is a "GC Explicit..." which I suspect has to do with garbage collection. What is the proper way to do what I am trying to do?

Related

Dependency Injection: How to get access to the corresponding ProductView that executes the Command?

I want to execute commands for each product view. Consider 10 products views, and each of them can execute the PrintProductViewCommand. This command, takes in constructor a ProductView and prints its name. Since it is #Injectable, the container will create a new ProductView each time the command is created. The following example shows what I want to do:
public class InjectionTest {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(ProductView.class);
bind(CommandExecutor.class);
bind(PrintProductViewNameCommand.class);
install(new FactoryModuleBuilder().implement(ProductView.class, ProductView.class)
.build(ProductViewFactory.class));
}
});
List<ProductView> productViews = new ArrayList<>();
ProductViewFactory factory = injector.getInstance(ProductViewFactory.class);
for (int i = 0; i < 10; i++) {
productViews.add(factory.create("Name: " + String.valueOf(i)));
}
System.out.println("Done creating");
//Now sometime in future, each product view calls print method
productViews.forEach(ProductView::print);
}
private static interface ProductViewFactory {
ProductView create(String name);
}
private static class ProductView {
private String name; //simulate a property
private CommandExecutor executor;
public ProductView() {
//Guice throws exception when this is missing
//Probably because it is being asked in PrintProductViewCommand
}
#AssistedInject
public ProductView(#Assisted String name, CommandExecutor executor) {
this.name = name;
this.executor = executor;
}
public String getName() {
return name;
}
//assume some time product view it self calls this method
public void print() {
executor.execute(PrintProductViewNameCommand.class);
}
}
#Singleton
private static class CommandExecutor {
#Inject
private Injector injector;
public void execute(Class<? extends Command> cmdType) {
injector.getInstance(cmdType).execute();
}
}
private static class PrintProductViewNameCommand implements Command {
private ProductView view;
#Inject
public PrintProductViewNameCommand(ProductView view) {
this.view = view;
}
#Override
public void execute() {
//Want to print "Name: something" here
System.out.println(view.getName());
}
}
private static interface Command {
void execute();
}
}
This problem is solved if I add a parameter to Command interface, and make it Command<T>. Then CommandExecutor will have this method:
public <T> void execute(Class<? extends Command<T>> cmdType, T parameter) {
injector.getInstance(cmdType).execute(parameter);
}
So, my PrintProductViewNameCommand is now class PrintProductViewNameCommand implements Command<ProductView>, and in product view :
public void print() {
executor.execute(PrintProductViewNameCommand.class,this);
}
However, the Command Pattern has no parameter in execute(). I have also seen somewhere that adding a parameter is an anti-pattern.
Of course, the command is simple. Assume that the command has other dependencies too, like Services etc.
Is there a way I can achieve it? Perhaps I am doing something wrong, probably with the whole DI situation.
When not using dependency injection, I would do something like this:
ProductView view = new ProductView();
Command command = new PrintProductViewNameCommand(view);
view.setPrintCommand(command);
But how to it while using DI?
So this works, although I'm not sure if it's 100% what you want to do.
public class InjectionTest {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(CommandExecutor.class);
bind(ProductView.class);
install(new FactoryModuleBuilder()
.implement(ProductView.class, ProductView.class)
.build(ProductViewFactory.class));
install(new FactoryModuleBuilder()
.implement(PrintProductViewNameCommand.class, PrintProductViewNameCommand.class)
.build(PrintProductViewNameCommand.Factory.class));
}
});
ProductViewFactory factory = injector.getInstance(ProductViewFactory.class);
List<ProductView> productViews = new ArrayList<>();
for (int i = 0; i < 10; i++) {
productViews.add(factory.create("Name: " + i));
}
System.out.println("Done creating");
//Now sometime in future, each product view calls print method
productViews.forEach(ProductView::print);
}
private interface ProductViewFactory {
ProductView create(String name);
}
private static class ProductView {
private String name;
private CommandExecutor executor;
private PrintProductViewNameCommand printProductViewNameCommand;
#AssistedInject
public ProductView(#Assisted String name, PrintProductViewNameCommand.Factory printProductViewNameCommandFactory, CommandExecutor executor) {
this.name = name;
this.executor = executor;
this.printProductViewNameCommand = printProductViewNameCommandFactory.create(this);
}
public ProductView() {}
public String getName() {
return name;
}
//assume some time product view it self calls this method
public void print() {
executor.execute(printProductViewNameCommand);
}
}
#Singleton
private static class CommandExecutor {
public void execute(Command command) {
command.execute();
}
}
private static class PrintProductViewNameCommand implements Command {
private final ProductView view;
#AssistedInject
public PrintProductViewNameCommand(#Assisted ProductView view) {
this.view = view;
}
static interface Factory {
PrintProductViewNameCommand create(ProductView productView);
}
#Override
public void execute() {
//Want to print "Name: something" here
System.out.println(view.getName());
}
}
private static interface Command {
void execute();
}
}
Basically what you're running into is a cyclic dependency problem (https://github.com/google/guice/wiki/CyclicDependencies#use-factory-methods-to-tie-two-objects-together) that's also exasperated by a bit by the fact that you have an additional AssistedInject in the ProductView.
By the way I'm using Guice 3 in this example.

Implementing a design pattern in a Database project

I am at my last year at the university and working on my final project with a group of friends.
I am responsible on implementing the database (using google firestore in java) and i am trying to implement it using a design pattern.
I found the adapter quiet useful, as I can create an interface called:
GenericDB, which contains all the methods the database needs to use.
A concrete class, let's call her FirestoreDB which implements it,
and an Adapter, which also implements the GenericDB, and holds an Instance Of GenericDB as a variable, so I can choose at run time which db I will want to use (maybe in the future the db would change)
Here is some basic code:
public interface GenericDB {
boolean add(String... args);
boolean delete(String... args);
boolean get(String... args);
boolean changePassword(String... args);
}
public class FirestoreDB implements GenericDB {
private final Firestore db;
public FirestoreDB() {
FirestoreOptions firestoreOptions =
FirestoreOptions.getDefaultInstance().toBuilder()
.setProjectId(Constants.PROJECT_ID)
.build();
this.db = firestoreOptions.getService();
}
public boolean add(String... args) {
return true;
}
public boolean delete(String... args) {
return false;
}
public boolean get(String... args) {
return false;
}
public boolean changePassword(String... args) {
return false;
}
}
public class Adapter implements GenericDB {
private GenericDB db;
public Adapter(GenericDB db){
this.db = db;
}
public boolean add(String... args) {
return this.db.add(args);
}
public boolean delete(String... args) {
return db.delete(args);
}
public boolean get(String... args) {
return db.get(args);
}
public boolean changePassword(String... args) {
return db.changePassword(args);
}
}
public class DatabaseCreator {
public GenericDB getDB(DATABASE database) {
switch (database) {
case FIRESTORE:
return new FirestoreDB();
default:
return null;
}
}
DatabaseCreator database = new DatabaseCreator();
GenericDB db = database.getDB(EXTRA.DATABASE.FIRESTORE);
Adapter ad = new Adapter(db);
System.out.println(ad.add("1"));
Is this a good use of the adapter pattern?
Is this a good use of the adapter pattern?
What you call Adapter, is not an Adapter. Purpose of Adapter is to convert interface of the class to another interface expected by the client. But your 'adapter' implements the same GenericDB interface as the adaptee it wraps - no conversion happens here.
The closest one to Adapter is your FirestoreDB class. It is intended to convert the interface of Firestore to the interface GenericDB required by your code. Of course there is still small chance that Google will change Firestore to implement your GenericDB interface. Until then you should use an adapter.
To make FirestoreDB a proper adapter, you should pass adaptee (Firestore object) to the constructor of adapter, and later call it in the GenericDB methods implementation:
public class FirestoreAdapter implements GenericDB {
private final Firestore db;
public FirestoreAdapter(Firestore db) { // pass adaptee to adapter
this.db = db;
}
public boolean add(...) {
// DocumentReference docRef = db.collection(colName).document(docId);
// etc
}
// etc
}
This adapter could be passed to the code which expects GenericDB interface and knows nothing about Firestore interface:
FirestoreOptions firestoreOptions =
FirestoreOptions.getDefaultInstance().toBuilder()
.setProjectId(Constants.PROJECT_ID)
.build();
Firestore firestore = firestoreOptions.getService(); // but your code requires GenericDB
GenericDB db = new FirestoreAdapter(firestore); // adapt Firestore interface
// use db here as if Firestore was implementing your GenericDB interface
You can write adapters for another type of database in the same way. But... usually, you don't use some abstract database interface, because databases are very different with different sets of features. Trying to find some intersection of features supported by all databases might be not a great idea (unless you writing CosmosDB). Usually, you will work with higher-level abstractions, like Repositories.
You should use Command Design Pattern it more flexible than Adapter in your case
Example:
import java.util.HashMap;
import java.util.Map;
// demo for firestore
class Firestore {
private Map<Object, Object> map = new HashMap<>();
public void add(Object id, Object object) {
map.put(id, object);
}
public Object get(Object id) {
return map.get(id);
}
}
interface FirestoreAware {
void setFirestore(Firestore firestore);
}
enum CommandType {
ADD,
DELETE,
GET,
CHANGE_PASSWORD,
GET_USER
}
interface Command {
CommandType getType();
}
class GetCommand implements Command {
private int id;
public GetCommand id(int id) {
this.id = id;
return this;
}
public int getId() {
return id;
}
#Override
public CommandType getType() {
return CommandType.GET;
}
}
class AddCommand implements Command {
private int id;
private String jsonData;
public AddCommand id(int id) {
this.id = id;
return this;
}
public AddCommand jsonData(String jsonData) {
this.jsonData = jsonData;
return this;
}
public int getId() {
return id;
}
public String getJsonData() {
return jsonData;
}
#Override
public CommandType getType() {
return CommandType.ADD;
}
}
interface CommandHandler<C> {
Object handle(C cmd);
}
abstract class CommandFirestoreHandler<C>
implements CommandHandler<C>, FirestoreAware {
protected Firestore firestore;
#Override
public void setFirestore(Firestore firestore) {
this.firestore = firestore;
}
}
class AddCommandHandler extends CommandFirestoreHandler<AddCommand> {
#Override
public Object handle(AddCommand cmd) {
firestore.add(cmd.getId(), cmd.getJsonData());
return Boolean.TRUE;
}
}
class GetCommandHandler extends CommandFirestoreHandler<GetCommand> {
#Override
public Object handle(GetCommand cmd) {
return firestore.get(cmd.getId());
}
}
interface GenericDB {
<T> T execute(Command cmd);
}
class FirestoreDB implements GenericDB {
private final Firestore firestore;
private final Map<CommandType, CommandHandler> handlers;
public FirestoreDB() {
this(new Firestore());
}
public FirestoreDB(Firestore firestore) {
this.firestore = firestore;
this.handlers = new HashMap<>();
// demo add default command handlers
this.addHandler(CommandType.ADD, new AddCommandHandler());
this.addHandler(CommandType.GET, new GetCommandHandler());
}
public void addHandler(CommandType commandType, CommandHandler handler) {
if(handler instanceof FirestoreAware)
((FirestoreAware)handler).setFirestore(firestore);
this.handlers.put(commandType, handler);
}
#Override
public <T> T execute(Command cmd) {
CommandHandler handler = handlers.get(cmd.getType());
return (T)handler.handle(cmd);
}
}
class DatabaseCreator {
public GenericDB getDB(String database) {
switch (database) {
case "FIRESTORE":
return new FirestoreDB();
default:
return null;
}
}
}
public class GenericDBDemo {
public static void main(String[] args) {
DatabaseCreator database = new DatabaseCreator();
GenericDB db = database.getDB("FIRESTORE");
db.execute(new AddCommand().id(1).jsonData("{'_id': 1, 'name' : 'hello world'}"));
System.out.println(db.execute(new GetCommand().id(1)).toString());
}
}

Is there a "clean" way to automatically un-register a listener in Java?

I believe I've seen variants of this question, but no "definitive answer". In the code below, I understand that SomeEventManager holds a reference to someImplClassTwo.myEventListenerA and someImplClassTwo.myEventListenerB, and that this does not allow for someImplClassTwo to be garbage collected, and this results in the output generated the second time someEventManager.notifyListeners() is invoked.
But, I'd really like for users of SomeImplClass not to have to know that there are listeners involved in the implementation, and that these listeners need to be manually un-registered (i.e., SomeImplClass.releaseListeners()) before releasing the SomeImplClass object.
Is there a clean/accepted way of doing this?
p.s. I've already played with finalize(), just for fun, and confirmed that GC is not even attempted in this case, for either instance of SomeImplClass. So, that seems to be a non-starter as a potential solution.
Test Driver
public class TestDriver {
public static void main(String[] args) {
SomeEventManager someEventManager = SomeEventManager.getInstance();
SomeImplClass someImplClassOne = new SomeImplClass("One");
SomeImplClass someImplClassTwo = new SomeImplClass("Two");
someEventManager.notifyListeners();
someImplClassOne.releaseListeners();
someImplClassOne = null;
someImplClassTwo = null;
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
someEventManager.notifyListeners();
}
}
Event Interface
public interface SomeEventListener {
public void handleSomeEvent();
}
Event Manager
import java.util.ArrayList;
import java.util.List;
public class SomeEventManager {
private static SomeEventManager eventManager = null;
private List<SomeEventListener> listeners = null;
private SomeEventManager() {
listeners = new ArrayList<SomeEventListener>();
}
public static SomeEventManager getInstance() {
if (eventManager == null) {
eventManager = new SomeEventManager();
}
return eventManager;
}
public void addListener(SomeEventListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public void removeListener(SomeEventListener listener) {
listeners.remove(listener);
}
public void notifyListeners() {
for(SomeEventListener listener : listeners) {
listener.handleSomeEvent();
}
}
}
Event Listener Implementation
public class SomeImplClass {
private InnerEventListener myEventListenerA = null;
private InnerEventListener myEventListenerB = null;
private String id = null;
public SomeImplClass(String id) {
this.id = id;
myEventListenerA = new InnerEventListener(id + "_A");
myEventListenerB = new InnerEventListener(id + "_B");
}
public void releaseListeners() {
myEventListenerA.unregisterListener();
myEventListenerB.unregisterListener();
}
private class InnerEventListener implements SomeEventListener {
private SomeEventManager someEventManager = null;
private String id = null;
public InnerEventListener(String id) {
someEventManager = SomeEventManager.getInstance();
this.id = id;
registerListener();
}
public void registerListener() {
someEventManager.addListener(this);
}
public void unregisterListener() {
someEventManager.removeListener(this);
}
public void handleSomeEvent() {
System.out.println("InnerEventListener->" + id);
}
}
}
The solution we use is to have the listener automatically unregister itself if it gets called and the thing it's updating has been collected.
It looks a bit like this:
private static class InnerEventListener implements SomeEventListener {
private final WeakReference<ThingToUpdate> thingRef;
public InnerEventListener(ThingToUpdate thing) {
thingRef = new WeakReference<>(thing);
}
#Override
public void handleSomeEvent(SomeEvent event) {
ThingToUpdate thing = thingRef.get();
if (thing != null) {
thing.updateSomehow();
} else {
((SomeEventedThing) event.getSource())
.removeSomeEventListener(this);
}
}
}
//...
SomeEventedThing eventedThing;
ThingToUpdate thingToUpdate;
//...
eventedThing.addListener(new InnerEventListener(thingToUpdate));
I wouldn't say it's a perfect solution because the listener sticks around until it gets an event, and it's still somewhat dependent on garbage collection. We've been trying to replace it with explicit removal where possible, usually on addNotify/removeNotify on GUI components.

How to properly convert Listeners to Reactive (Observables) using RxJava?

I'm using a multiplayer Game Client that's called AppWarp (http://appwarp.shephertz.com), where you can add event listeners to be called back when event's happen, let's assume we'll be talking about the Connection Listener, where you need to implement this interface:
public interface ConnectionRequestListener {
void onConnectDone(ConnectEvent var1);
void onDisconnectDone(ConnectEvent var1);
void onInitUDPDone(byte var1);
}
My goal here is to mainly create a Reactive version of this client to be used in my Apps Internally instead of using the Client itself directly (I'll also rely on interfaces later instead of just depending on the WarpClient itself as in the example, but that's not the important point, please read my question at the very end).
So what I did is as follows:
1) I introduced a new event, named it RxConnectionEvent (Which mainly groups Connection-Related events) as follows:
public class RxConnectionEvent {
// This is the original connection event from the source client
private final ConnectEvent connectEvent;
// this is to identify if it was Connection / Disconnection
private final int eventType;
public RxConnectionEvent(ConnectEvent connectEvent, int eventType) {
this.connectEvent = connectEvent;
this.eventType = eventType;
}
public ConnectEvent getConnectEvent() {
return connectEvent;
}
public int getEventType() {
return eventType;
}
}
2) Created some event types as follows:
public class RxEventType {
// Connection Events
public final static int CONNECTION_CONNECTED = 20;
public final static int CONNECTION_DISCONNECTED = 30;
}
3) Created the following observable which emits my new RxConnectionEvent
import com.shephertz.app42.gaming.multiplayer.client.WarpClient;
import com.shephertz.app42.gaming.multiplayer.client.events.ConnectEvent;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;
public class ConnectionObservable extends BaseObservable<RxConnectionEvent> {
private ConnectionRequestListener connectionListener;
// This is going to be called from my ReactiveWarpClient (Factory) Later.
public static Observable<RxConnectionEvent> createConnectionListener(WarpClient warpClient) {
return Observable.create(new ConnectionObservable(warpClient));
}
private ConnectionObservable(WarpClient warpClient) {
super(warpClient);
}
#Override
public void call(final Subscriber<? super RxConnectionEvent> subscriber) {
subscriber.onStart();
connectionListener = new ConnectionRequestListener() {
#Override
public void onConnectDone(ConnectEvent connectEvent) {
super.onConnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_CONNECTED));
}
#Override
public void onDisconnectDone(ConnectEvent connectEvent) {
super.onDisconnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_DISCONNECTED));
}
// not interested in this method (for now)
#Override
public void onInitUDPDone(byte var1) { }
private void callback(RxConnectionEvent rxConnectionEvent)
{
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(rxConnectionEvent);
} else {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
};
warpClient.addConnectionRequestListener(connectionListener);
subscriber.add(Subscriptions.create(new Action0() {
#Override
public void call() {
onUnsubscribed(warpClient);
}
}));
}
#Override
protected void onUnsubscribed(WarpClient warpClient) {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
4) and finally my BaseObservable looks like the following:
public abstract class BaseObservable<T> implements Observable.OnSubscribe<T> {
protected WarpClient warpClient;
protected BaseObservable (WarpClient warpClient)
{
this.warpClient = warpClient;
}
#Override
public abstract void call(Subscriber<? super T> subscriber);
protected abstract void onUnsubscribed(WarpClient warpClient);
}
My question is mainly: is my implementation above correct or should I instead create separate observable for each event, but if so, this client has more than 40-50 events do I have to create separate observable for each event?
I also use the code above as follows (used it in a simple "non-final" integration test):
public void testConnectDisconnect() {
connectionSubscription = reactiveWarpClient.createOnConnectObservable(client)
.subscribe(new Action1<RxConnectionEvent>() {
#Override
public void call(RxConnectionEvent rxEvent) {
assertEquals(WarpResponseResultCode.SUCCESS, rxEvent.getConnectEvent().getResult());
if (rxEvent.getEventType() == RxEventType.CONNECTION_CONNECTED) {
connectionStatus = connectionStatus | 0b0001;
client.disconnect();
} else {
connectionStatus = connectionStatus | 0b0010;
connectionSubscription.unsubscribe();
haltExecution = true;
}
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
fail("Unexpected error: " + throwable.getMessage());
haltExecution = true;
}
});
client.connectWithUserName("test user");
waitForSomeTime();
assertEquals(0b0011, connectionStatus);
assertEquals(true, connectionSubscription.isUnsubscribed());
}
I suggest you avoid extending the BaseObservable directly since it's very error prone. Instead, try using the tools Rx itself gives you to create your observable.
The easiest solution is using a PublishSubject, which is both an Observable and a Subscriber. The listener simply needs to invoke the subject's onNext, and the subject will emit the event. Here's a simplified working example:
public class PublishSubjectWarpperDemo {
public interface ConnectionRequestListener {
void onConnectDone();
void onDisconnectDone();
void onInitUDPDone();
}
public static class RxConnectionEvent {
private int type;
public RxConnectionEvent(int type) {
this.type = type;
}
public int getType() {
return type;
}
public String toString() {
return "Event of Type " + type;
}
}
public static class SimpleCallbackWrapper {
private final PublishSubject<RxConnectionEvent> subject = PublishSubject.create();
public ConnectionRequestListener getListener() {
return new ConnectionRequestListener() {
#Override
public void onConnectDone() {
subject.onNext(new RxConnectionEvent(1));
}
#Override
public void onDisconnectDone() {
subject.onNext(new RxConnectionEvent(2));
}
#Override
public void onInitUDPDone() {
subject.onNext(new RxConnectionEvent(3));
}
};
}
public Observable<RxConnectionEvent> getObservable() {
return subject;
}
}
public static void main(String[] args) throws IOException {
SimpleCallbackWrapper myWrapper = new SimpleCallbackWrapper();
ConnectionRequestListener listner = myWrapper.getListener();// Get the listener and attach it to the game here.
myWrapper.getObservable().observeOn(Schedulers.newThread()).subscribe(event -> System.out.println(event));
listner.onConnectDone(); // Call the listener a few times, the observable should print the event
listner.onDisconnectDone();
listner.onInitUDPDone();
System.in.read(); // Wait for enter
}
}
A more complex solution would be to use one of the onSubscribe implementations to create an observable using Observable.create(). For example AsyncOnSubscibe. This solution has the benefit of handling backperssure properly, so your event subscriber doesn't become overwhelmed with events. But in your case, that sounds like an unlikely scenario, so the added complexity is probably not worth it.

Garbage Collection of Listeners clarification (Java/Android)

Assume the following two classes:
public class Network {
private static Network instance;
public Network() {
instance = this;
}
public static Network getInstance() {
return instance;
}
public interface Listener {
public void event(String msg);
};
ArrayList<Listener> listeners = new ArrayList<Listener>();
public void addListener(Listener listener) {
listeners.add(listener);
}
}
public class Act1 extends Activity implements Network.Listener {
#Override
public void onCreate(Bundle b) {
Network.getInstance().addListener(this);
}
public void event(String msg) {
// do nothing
}
}
public class Act2 extends Activity implements Network.Listener {
#Override
public void onCreate(Bundle b) {
Network.getInstance().addListener(new Network.Listener() {
public void event(String msg) {
// do nothing
}
);
}
public void event(String msg) {
}
}
Will either of the Activities leak once a user moves on to another Activity? Will either Activity be prevented from getting GCed? Are there any problems with the Listener implementation above?
Your example has some mistakes.
For example you never instantiate Network and every time you instantiate it, the static field will reference another instance. A more proper way to write Network would be the following
public class Network {
private static final Network INSTANCE = new Network();
private Network() {/*empty*/}
public static Network get() {
return INSTANCE;
}
//rest of the code ommitted
}
However, if you are not removing the Activity instances from the Network singleton (that static field instance in the Network class - assuming you initialize it at some point), then that instance will always have a reference to your Activity objects that were added to it's ArrayList. This way they cannot be garbage collected.

Categories

Resources