Firebase Database for Unity3d Android ValueChanged unsubscribe issues - android

I have problem with Unity3d SDK.
I subscribe to ValueChanged event and when first time it invokes I unsubscribe from the handler.
In Unity everything works fine.
But when I build project for Android, unsubscribe fails: after unsubscribe I still handle events in handler.
Here is the code:
public void CheckUserExists()
{
FirebaseDatabase.DefaultInstance
.GetReference("users").Child(primary_key)
.ValueChanged += CheckUserExistsHadler;
}
void CheckUserExistsHadler(object sender, ValueChangedEventArgs e)
{
FirebaseDatabase.DefaultInstance
.GetReference("users").Child(primary_key)
.ValueChanged -= CheckUserExistsHadler;
if (e.Snapshot == null || e.Snapshot.Value == null)
{
print("user_exists");
}
else
{
print("user_not_exists");
}
}

Thanks for the tip. I changed to
user_reference = FirebaseDatabase.DefaultInstance.GetReference("users").Child(primary_key);
...
user_reference.ValueChanged += CheckUserExistsHadler;
...
user_reference.ValueChanged -= CheckUserExistsHadler;
and it works fine

I Just ran into this issue on Android, worked in Editor.
What I found was that when I re-created the database reference at the point of un-subscribing, using the exact same reference string as I used to add the listener it would not properly un-subscribe in Android.
The solution I used was the same as Bestlis above, I created a DatabaseReference variable, which I used to sub and un-sub from, now it works.
It's an odd problem to have, it's like FirebaseDatabase.DefaultInstance.GetReference changes during operation?

For some reason, any firebase calls made from a callback fail(Getvalue, updatechildren, subscribe/unsubscribe, all that). Your best bet is to have it put into an action queue, and have a monobehavior check the queue/list and call its contents from the main thread.

Related

How to know an action is done globally react native

This is really common that i want to know an action is done and then do sth after that. for this we usually use events but i don't know how to use it in my case.
my scenario: There is an SplashScene which shows some animations for a constant time, after that time i navigate to my HomeScene. there are some other initializations which i don't want to be done unless SplashScene is gone and we r in HomeScene.
those initializations are in App component. and what im doing is that because the SplashScene animation time is constant i use a timeout to init things.
// Constants.ts
export const GlobalStaticData = {
initialDuration: 5000 // ms
}
// App
public componentDidMount() {
setTimeout(() => {
// initialize things
}, GlobalStaticData.initialDuration) // show dialogs after splash loading time
}
// SplashScene
private onAnimationEnd = () => {
NavigationActions.navigate(HomeScene)
}
but i know this is not good at all, i already experience sometimes which timing doesn't work as expected and things get initialized when app is still in SplashScene.
i was thinking for way to use events but i dont know how do that. what i want to listen to a value e.g called isSplashLoadCompleted in App component and in splash change that value when its works are done. then in App its event listener is called and initialing get started.
You can write a basic event system to subscribe to an event and then emit the event when certain thing happened on the other page:
const subscribers = {}
// Subscribe to loading your target page here Ex subsciber('home_load',()=>{ Your Logic })
const subscribe = (event,callback)=>{
if(subscribers[event] == null){ subscribers[event] = {}}
subscribers[event].push(callback)
}
const unSubscribe = (event,callback)=>{
....
}
// Call this inside your target page componentDidMount Ex: emitEvent('home_load',Some data or null)
const emitEvent = (event,data)=>{
if(subscribers[event]!=null && subscibers[event].length > 0){
for(const cb of subscribers[event]){
if(cb != null){cb()}
}
}
}
Sounds like the you want to trigger specific code when different scenes are loaded. I would recommend moving your animation/initialization logic into the compomentDidMount() for the respective scenes - SplashScene and HomeScene.
You're running into issues because your animation/initialization code is completely decoupled from your scenes. Couple the logic to the componentDidMount for these scenes and you won't have to worry about timing issues.

Why is Facebook's Unity SDK Not Logging Events To Analytics?

For some reason, I am unable to get the FB.LogAppEvent to work inside an android application built with Unity.
Based on the documentation I've read, the code below should work. But it's not producing results inside the analytics dashboard. You'll notice a method that produces an Android toast that confirms activation. This toast does appear on application start. I've tried multiple event types, including custom types from code generated by Facebook's event generator in the event documentation.
https://developers.facebook.com/docs/app-events/unity
https://developers.facebook.com/docs/unity/reference/current/FB.LogAppEvent/
private void Awake()
{
if (!FB.IsInitialized)
FB.Init( () => { OnInit(); } );
else
ActivateFacebook();
}
private void OnInit()
{
if (FB.IsInitialized)
ActivateFacebook();
else
ShowAndroidToastMessage("Failed To Initialize Facebook..");
}
private void ActivateFacebook()
{
FB.ActivateApp();
ShowAndroidToastMessage("Facebook Activated..");
FB.LogAppEvent(AppEventName.ActivatedApp);
}
I suppose the problem is in the way you send event
There are two methods for that:
LogAppEvent(string logEventName);
LogAppEvent(string logEventName, float valueToSum, Dictionary parameters = null);
You are using second method with "valueToSum" = 0, and that indicates there is nothing to sum, so your event probably gets skipped at some point.
You should use the first method
FB.LogAppEvent(AppEventName.ActivatedApp);
Also make sure your analytics is enabled in dashboard.
Do you see any built in analytic events? Feg. App Launches and other Standard events should be visible out of the box.
For me, LogAppEvent(...) successfully works with the Facebook Events Tracker and Analytics when you do a development build with Unity. When I switch to a release build, I then do not get any of the LogAppEvents other than the ActivateApp() notification.
Will update my answer when I get it working with a release build.

How to trigger / debug backdoor functionality in Xamarin.Forms.UITesting?

I'm trying to add a BackdoorMethod to a Xamarin.Forms application to bypass the login (IDP - opened in chrome browser) step. I have the feeling that the method is not getting triggered, but not sure, and I don't know how could I make sure about it.
I've read the documentation here: https://learn.microsoft.com/en-us/appcenter/test-cloud/uitest/working-with-backdoors
Check this thread: https://forums.xamarin.com/discussion/85821/xamarin-uitest-backdoor-on-droid-with-splash-screen-how-do-i-access-my-mainactivity
Checked this example: https://github.com/brminnick/UITestSampleApp/tree/master/Src
In the MainActivity.cs file I've defined the BackdoorMethod:
[Preserve, Export(nameof(BypassLoginScreen))]
public string BypassLoginScreen()
{
// some additional code here. the code is working, when I called it
// directly from OnCreate it was executed without any error
return "called";
}
From the test case i'm trying to invoke it like:
public constructorMethod(Platform platform)
{
this.platform = platform;
app = AppInitializer.StartApp(platform);
var result = app.Invoke("BypassLoginScreen"); // result == "<VOID>"
}
I'm not getting any error message, the method simply not called, or not returns anything. (or i don't know what's happening there with it, because breakpoint also not working as the app started from the device)
This should be already working. I have similar code and it works for me.
you can add inside your function
Android.Util.Log.WriteLine(Android.Util.LogPriority.Info, "BypassLoginScreen", $"Some text as info");
And observe the result in Device Logs, Filter by BypassLoginScreen to see if there is any log created with the tag BypassLoginScreen

Java - Android : Thread being called (run) twice

I would like some help regarding Java - Android MultiThreading
While learning to develop my app in a multi-threading way in order to take advantage of the ever-growing multi-core devices market share (most devices are quad core now, some even octo-core), I ran in a situation where my threads are either being calling twice or running twice.
I just don't why and how.
[EDIT 3]
Alright, I narrowed down the issue : I called the AsyncTask from the onResume() method. Although my app did not lost focus (which would mean a call to onPause() then back to onResume() upon return of focus in which case my threads would be run twice) during the tests, I solved the issue by moving away the call to FetchFriendsList to another place.
So far so good, but since in my tests the app did not loose focus or perhaps it did but I could not witness it (!), I think there is another reason behind so I'd say my problem is not entirely solved ... at least for the moment. It does work though. Perhaps I did solve the issue but I do not know how :(
[end of EDIT 3]
I am implementing last Facebook SDK and I am using it to fetch the end-user friends list, which seems to do the work.
Since I am running this operation in an AsyncTask, I am not using request.executeAsync().
Instead I am using request.executeAndWait(). Facebook JavaDoc does state that this method must only be used if I am not in a the Main UI Thread which is my case otherwise I would get a NetworkOnMainThreadException.
Anyway, this is where the weird behavior is happening.
private final ArrayList<GraphUser> userFriendsList = new ArrayList<GraphUser>();
public final void fetchFriendsList() {
if (this.session != null && this.session.isOpened()) {
final Request requestUserFriendsList = Request.newMyFriendsRequest(
this.session, new Request.GraphUserListCallback()
public final void onCompleted(final List<GraphUser> users, final Response response) {
if (users != null && users.size() > 0) {
Log.v("Retrieved Friends List -> ", String.valueOf(users.size()));
userFriendsList.addAll(users);
}
}
}
);
if (this.asyncFlag)
requestUserFriendsList.executeAsync();
else
requestUserFriendsList.executeAndWait();
}
}
In my case, asyncFlag is set to false because I need to do stuff synchronously in that specific order :
Fetch User Friends List (not on the Main (UI) Thread)
Save friends list on device (separate new thread)
Save friends list on a server (separate new thread)
Following this pattern, the line userFriendsList.addAll(users); is called twice.
In the logcat, the Log.vis showed twice as well, and finally looking with the debugger, the content of the user friends list is made of duplicates.
But that's not all ... step 2 and 3 are indeed two separate threads which are both created and spawned within the same method : public final void asyncSaveFacebookFriendsList().
And guess what, this method is even called twice !
just why ?
At the beginning I was calling the method for step 2 and 3 like this :
[...]
userFriendsList.addAll(users);
asyncSaveFacebookFriendsList(); // it was private before
[...]
This is where the issue started as both line were running twice.
So I thought, alright, I'll call it later like this :
[...]
fetchFriendsList();
asyncSaveFacebookFriendsList(); // it is now public
[...]
But the issue remains still.
If I don't call public final void asyncSaveFacebookFriendsList(), then nothing is run twice.
Why does this issue happen ? Is there something I did not get in Java Threads ?
I do not think this is somehow related to the Facebook SDK because following the same pattern (and doing it also at the same time), I have the same issues when fetching and storing the end-user Twitter friends list.
So I do believe I am doing something wrong. Does someone have any idea in what possible case a thread is called twice ?
Note : all threads are started this way : thread.start(). I am not using any ThreadPool nor the ExecutorService.
In case you need more background context :
Content of AsyncTask : (no need to wonder why Void and Long, I remove the irrelevant code related to it)
private final class FetchFriendsLists extends AsyncTask<Long, Integer, Void> {
protected final Void doInBackground(final Long... params) {
if (params[0] != Long.valueOf(-1)) {
[...]
twitterAPI.fetchUserFriendsList();
publishProgress(1, -1);
}
if (params[1] == Long.valueOf(0)) {
[...]
facebookAPI.fetchFriendsList();
publishProgress(-1, 0);
}
return null;
}
protected final void onProgressUpdate(Integer... flags) {
super.onProgressUpdate(flags);
if (flags[0] != -1)
twitterAPI.asyncSaveFacebookFriendsList();
if (flags[1] == 0)
facebookAPI.asyncSaveFacebookFriendsList();
}
}
As you can see, I start step 2 and 3 in onPublishProgress() which runs on the Main UI Thread. Brefore it was in the doInBackground() method : the issue happens in both cases!
[EDIT]
After further test, it would seem any kind of code is in fact running twice.
I created a simple method called test in which in print a counter. The counter incremente twice as well !
Why you use onProgressUpdate?¿?
onProgressUpdate(Progress...), [...]. This method is used to display any form of progress in the
user interface while the background computation is still executing.
For instance, it can be used to animate a progress bar or show logs in
a text field.
This is used not at the finish of the petition, but when progress increased.
Read this:
http://developer.android.com/reference/android/os/AsyncTask.html
You need to use:
protected void onPostExecute(Long result) {

In a Unity3D - Android project .. how to get memory warnings?

How to be alerted of memory warnings? Unity3D, building to Android.
Cheers.
You can subscribe to Application.lowMemory Documentation
For example, in some monoBehaviour starting your game:
private void Start()
{
Application.lowMemory += ReportSystemLowMemory;
}
private void ReportSystemLowMemory()
{
Debug.LogWarning("Warning: Low memory");
}
Be sure to don't subscribe ReportSystemLowMemory more than once.
Also unsubscribing it would be a good practice, ie Application.lowMemory -= ReportSystemLowMemory when you are close your app/game.
There is no inbuilt function for this in Android as far as I know.

Categories

Resources