NicCoe
NicCoe

Reputation: 419

Kotlin - Call class method from object

Will try to keep this as concise as possible...

I would like to have a method in my MainActivty class, say updateUI().

I have another file that is an object called FBManager. That object essentially holds "static" firebase access methods.. let's say signInUser()

From the Activity I call FBManager.signInUser()... It does some logic and moves through 2 private methods and at the last private method, I would like to essentially call MainActivity.updateUI()…

This can't be done as kotlin doesn't have static methods and can't make updateUI() static. MainActivity().updateUI() compiles but is incorrect and don't want to instantiate a new MainActivity. Lastly, I thought of passing the activity into the first constructor like FBManager.signInUser(this)... But after signInUser(), it goes to an override method that can only take a bundle as an optional input (and I don't believe you can put activities into a bundle), thus I can't pass the activity reference to the final private method.....

Edit: Further elaboration

object FBManager {

fun signInUser() {
// Create intent
startActivityForResult(intent)
}

override fun onActivityResult(some intent stuff) {
//Try catch block. In try block call
firebaseAuth(Google account)
}

fun firebaseAuth(acct: GoogleSignInAccount) {
//More logic and an .onCompleteListener

// Inside .onCompeteListener, which is the problem....
MainActivity.updateUI()
}
}

Apologies for layout... Typing on my phone...

-end edit-

I hope all that makes sense as I'm new to programming and find it difficult to explain my problems (since if I truely understood them I could come up with a solution..)

So as per the title, is there any other way to do this... To call a method in MainActivity from an object FBManager?

Upvotes: 1

Views: 7875

Answers (3)

redlabrat
redlabrat

Reputation: 507

You can create interface to make interaction between your FBManager and MainActivity. For example:

interface Updatable {
    void updateUi();
}

MainActivity:

class MainActivity implements Updatable {
    ...
    @Override
    void updateUi()
    ...
    FBManager.signInUser(this)
    ...
}

FBManager:

object FBManager {
    ...
    void signInUser(Updatable callback) {
        ...
        callback.updateUi()
        ...
    }
}

Upvotes: 0

user10053723
user10053723

Reputation:

what about this example? activity

class ExampleActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_example)

        FBManager.signInUser {
            updateUI()
        }
    }

    private fun updateUI() {
        // update UI
    }
}

and FBManager object

object FBManager {
    fun signInUser(callback: () -> Unit) {
        // do work and then
        callback()
    }
}

Upvotes: 9

gi097
gi097

Reputation: 7701

and can't make updateUI() static.

True! You want to minimize the usage of static stuff in any of your activities.

I don't know how good you are at Java, but I use the so called observer-pattern a lot for this kind of problems. You might need to convert it to Kotlin.

If the MainActivity is running, it registers to receive events from the FBManager.

I use the following code from Telegram quite a lot:

public class NotificationCenter {

    private static int totalEvents = 1;

    public static final int updateActivity = totalEvents++;

    private final SparseArray<ArrayList<Object>> observers = new SparseArray<>();
    private final SparseArray<ArrayList<Object>> removeAfterBroadcast = new SparseArray<>();
    private final SparseArray<ArrayList<Object>> addAfterBroadcast = new SparseArray<>();

    private int broadcasting = 0;

    public interface NotificationCenterDelegate {
        void didReceivedNotification(int id, Object... args);
    }

    private static volatile NotificationCenter Instance = null;

    public static NotificationCenter getInstance() {
        NotificationCenter localInstance = Instance;
        if (localInstance == null) {
            synchronized (NotificationCenter.class) {
                localInstance = Instance;
                if (localInstance == null) {
                    Instance = localInstance = new NotificationCenter();
                }
            }
        }
        return localInstance;
    }

    public void postNotificationName(final int id, final Object... args) {
        if (Thread.currentThread() == ApplicationLoader.applicationHandler.getLooper().getThread()) {
            postNotificationNameInternal(id, args);
        } else {
            ApplicationLoader.runOnUIThread(new Runnable() {
                @Override
                public void run() {
                    postNotificationNameInternal(id, args);
                }
            });
        }
    }

    private void postNotificationNameInternal(int id, Object... args) {
        broadcasting++;
        ArrayList<Object> objects = observers.get(id);
        if (objects != null && !objects.isEmpty()) {
            for (int a = 0; a < objects.size(); a++) {
                Object obj = objects.get(a);
                ((NotificationCenterDelegate) obj).didReceivedNotification(id, args);
            }
        }
        broadcasting--;
        if (broadcasting == 0) {
            if (removeAfterBroadcast.size() != 0) {
                for (int a = 0; a < removeAfterBroadcast.size(); a++) {
                    int key = removeAfterBroadcast.keyAt(a);
                    ArrayList<Object> arrayList = removeAfterBroadcast.get(key);
                    for (int b = 0; b < arrayList.size(); b++) {
                        removeObserver(arrayList.get(b), key);
                    }
                }
                removeAfterBroadcast.clear();
            }
            if (addAfterBroadcast.size() != 0) {
                for (int a = 0; a < addAfterBroadcast.size(); a++) {
                    int key = addAfterBroadcast.keyAt(a);
                    ArrayList<Object> arrayList = addAfterBroadcast.get(key);
                    for (int b = 0; b < arrayList.size(); b++) {
                        addObserver(arrayList.get(b), key);
                    }
                }
                addAfterBroadcast.clear();
            }
        }
    }

    public void addObserver(Object observer, int id) {
        if (broadcasting != 0) {
            ArrayList<Object> arrayList = addAfterBroadcast.get(id);
            if (arrayList == null) {
                arrayList = new ArrayList<>();
                addAfterBroadcast.put(id, arrayList);
            }
            arrayList.add(observer);
            return;
        }
        ArrayList<Object> objects = observers.get(id);
        if (objects == null) {
            observers.put(id, (objects = new ArrayList<>()));
        }
        if (objects.contains(observer)) {
            return;
        }
        objects.add(observer);
    }

    public void removeObserver(Object observer, int id) {
        if (broadcasting != 0) {
            ArrayList<Object> arrayList = removeAfterBroadcast.get(id);
            if (arrayList == null) {
                arrayList = new ArrayList<>();
                removeAfterBroadcast.put(id, arrayList);
            }
            arrayList.add(observer);
            return;
        }
        ArrayList<Object> objects = observers.get(id);
        if (objects != null) {
            objects.remove(observer);
        }
    }
}

Then make your MainActivity look like this:

public class MainActivity implements NotificationCenter.NotificationCenterDelegate {

    @Override
    public void onPause() {
        NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateActivity);
        super.onPause();
    }

    @Override
    public void onResume() {
        NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateActivity);
        super.onResume();
    }

    @Override
    public void didReceivedNotification(int id, Object... args) {
        if (id == NotificationCenter.updateActivity) {
            UpdateUI();
        }
    }
}

Then in your FBManager:

NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateActivity, optionalData);

See the other code from this implementation here: https://github.com/gi097/MyWindesheim/tree/master/app/src/main/java/com/giovanniterlingen/windesheim

Upvotes: 0

Related Questions