our application shows interstitial iAds after each played level.
At the moment a level finishes, we create the ad:
_interstitial = [[ADInterstitialAd alloc] init];
_interstitial.delegate = self;
and the delegate implements the following callback methods:
- (void)interstitialAdDidUnload:(ADInterstitialAd *)interstitialAd
{
[self finish];
}
- (void)interstitialAd:(ADInterstitialAd *)interstitialAd didFailWithError:(NSError *)error
{
[self finish];
}
- (void)interstitialAdDidLoad:(ADInterstitialAd *)interstitialAd
{
[_interstitial presentFromViewController:self];
}
- (void)interstitialAdActionDidFinish:(ADInterstitialAd *)interstitialAd
{
[self finish];
}
whereas the finish method cleans up things and forwards the user to the main menu.
from the moment the ad object is created until the finish method is called, a spinning wheel is displayed on the screen.
Now the thing is that if no ad is loaded (for example if no internet connection is available) none of the callback functions ever gets called, so we also add a NSTimer when creating the Ad and check back after 10 seconds, like this:
_interstitial = [[ADInterstitialAd alloc] init];
_interstitial.delegate = self;
_timer = [NSTimer scheduledTimerWithTimeInterval:10
target:self
selector:#selector(checkForAds:)
userInfo:nil
repeats:false];
-(void)checkForAds:(NSTimer *)timer
{
[_timer invalidate];
if(!_interstitial.loaded)
[self finish];
}
but this seems very unclean - and also it leads to a 10 seconds spinning wheel delay after each level if no internet connection is available for example (or if the connection is very bad).
so, my questions:
what's the proper way to deal with this? I feel a timer here is not the right thing.
I'm currently considering to create the Ad object before the level starts, and then after the level finishes immediately check the _interstitial.loaded property and show the ad in this case or skip over it otherwise, without using a timer. The problem is that a level session can take quite long (between 1 and 60 minutes I'd say) and I read that ads can expire, however there is no indication in the documentation how long it usually takes until ads expire and what happens in this case. Will the _interstitial.loaded property return false if the ad expired in the meantime in the background? is some callback function called when the ad expires? Is it a viable approach to create the ad object before a level starts (that is, 1-60 minutes before the ad actually gets displayed) and later just check if _interstitial.loaded is true and in this case display the ad?
Related
im working on a Game in Unity and want to Safes the User data in Firebase Realtime Database (Will just call it Firebase from now on).
I came up with the idea to create a GameObject, attach a Script (https://github.com/xBarkeeper/2DRun/blob/main/Assets/MainMenu/Scripts/MonoUser.cs) to it and load the Data in the Start scene. The Script had the ValueChanged Method from FireBase in it, so every time data in Firebase changed, it also get updated in the GameObject.
My Plan was to pass this GameObject through my entire Game, so i don't habe to matter about the Userdata anymore.
No I have two Problems with it:
When I move the Object from one Scene to another, the ValueChanged Method is not working anymore. (Not listening to the FireBase)
When I have a other GameObject that is using FireBase, it works completely fine until I use setDataBaseValues or ContinueWithOnMainThread. Both of them first runs when I stop my unity run. But then work successfully.
I don't really know what Code I should attach to this question.
For Example to Problem 2:
Debug.Log("Log 1");
DatabaseReference databaseReference = FirebaseDatabase.DefaultInstance.RootReference;
Debug.Log("Log 2");
this.userName = userName;
FirebaseDatabase.DefaultInstance
.GetReference(userName)
.GetValueAsync().ContinueWithOnMainThread(task =>
{
if (task.IsFaulted)
{
Debug.Log("Log 3");
}
else if (task.IsCompleted)
{
DataSnapshot snapshot = task.Result;
Debug.Log("Log 4");
this.uuid = snapshot.Child("uuid").GetValue(true).ToString();
Debug.Log("Log 5");
}
});
Log 2 is called directly. Log 4 is printed when I end my Game.
Also tried have a Scene loaded through my entire Game with the GameObject attached. But in the moment I load a new Scene, it also don't listen to the ValuesChanged Method anymore.
Isn't it possible to send a FireBase Object between Scenes with a working ValuesChanged?
Do I really need to create a FireBase Object in each scene, although then the data must always be downloaded again?
And why the setDatabaseValues Thread starts first on stoping my Unity Game?
For problem 1: is the gameObject marked as "DontDestroyOnLoad"?
When do you register the OnValueChanged () method?
Before doing anything, do you initialize Firebase Database?
For problem 2: use this code by substituting the line before Debug.Log ("Log 5”);
this.uuid = System.Convert.ToString(snapshot.Child("uuid").GetValue(true));
I usually use "Value" instead of "GetValue()", but it should be the same thing.
I have a WPF (MVVM with Prism) application
There are quite a lot of factors that can affect this problem, but I will try to boil it down.
Hopefully I can at least get some tips how to trouble shoot this.
I have a user control containing a datagrid and a typical Search-button. The grid is initially empty and on SearchCommand. The user control uses a class "AccountServiceGateway" (_accountSG below) to make a request to the server, and then fills datasource of the grid with the result. Pretty standard.
VM: Binding command to handler in ctor
...
SearchCommand = new DelegateCommand(async () => await SearchOnServer(new AccountFilterDTO()));
VM, Button handler implementation
private async Task<bool> SearchOnServer(AccountFilterDTO filter)
{
var searchAccountResults = await _accountSG.SearchAccounts(filter);
//AccountSearchResultList is an observable collection that is datasource for the grid
AccountSearchResultList = new ObservableCollection<AccountSearchResultDTO>(searchAccountResults);
}
// Account Service gateway, making a web request
protected async Task<T> GetFromUrl<T>(string urlPart)
{
...
var response = await _httpClient.GetAsync(url);
resStr = await response.Content.ReadAsStringAsync();
//convert to T and return
}
EDIT
When I replace the implementation of GetFromUrl() with
await Task.Delay(5000)
return [hardcoded list of T]
everything works ok (although the hardcoded list is only 5 items)
END EDIT
Now to my problem. Getting an answer from the server taks about 1-2secs, as expected. I can follow the code until my datasource is filled. But then the GUI freezes for roughly (10-)20 seconds before anything is displayed, then efter the freeze, everything is as expected.
Other things to notice is that user control is in a Prism-region, within a Telerik RadTabbedWindow, so if this looks ok ith might be something else.
So my main question is, why does it hang for 20 seconds, I suspect there is some threading problem, but if it where a deadlock, wouldnt it hang forever? Any way to trouble shoot this?
Has the view changed in some way so that list virtualisation has been effectively turned off?
eg. Parent ScrollerViewer been added
I want to store data in database in every minute . For the same what should I use Service, AsyncTask or anything else. I go through various link which made me more confused .
I read the developer guide and came to know about getWritableDatabase
Database upgrade may take a long time, you should not call this method from the application main thread,
Then first I think I will use AsyncTask then about this
AsyncTasks should ideally be used for short operations (a few seconds at the most.)
After that I think I can use Service then about Service
A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
Here I am not able to understand what should I use to store data in database periodically. Please help me here as struck badly.
Thanks in advance
you cant do a lot work on the UI thread, so making database operations you could choose different approaches, few of them that I prefer to use are listed below;
Create a thread pool and execute each database operation via a thread, this reduces load on UI thread, also it never initializes lot of threads.
You can use services for updating the database operations. since services running on UI thread you cant write your operations in Services, so that you have to create a separate thread inside service method. or you can use Intent service directly since it is not working on UI Thread.
here is developer documentation on thread pool in android
and this is the documentation for IntentService
UPDATE
This will send an intent to your service every minute without using any processor time in your activity in between
Intent myIntent = new Intent(context, MyServiceReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 60); // first time
long frequency= 60 * 1000; // in ms
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), frequency, pendingIntent);
Before that check if you really need a service to be started in each minute. or if you can have one service which checks for the data changes in each minute, starting new service would consume maybe more resources than checking itself.
UPDATE 2
private ping() {
// periodic action here.
scheduleNext();
}
private scheduleNext() {
mHandler.postDelayed(new Runnable() {
public void run() { ping(); }
}, 60000);
}
int onStartCommand(Intent intent, int x, int y) {
mHandler = new android.os.Handler();
ping();
return STICKY;
}
this is a simple example like that you can do
When using the authenticateHandler in iOS 6, game center won't present the login view if the user cancels it. I realize game center will auto lockout an app after 3 cancel attempts, but I'm talking about just 2 attempts. If they cancel the login, they have to leave the app and come back before game center will present the login even through the authenticateHandler is getting set again. Any ideas on how to handle this case in iOS 6?
It works fine when using the older authenticateWithCompletionHandler method:
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_6_0
GKLocalPlayer.localPlayer.authenticateHandler = authenticateLocalPlayerCompleteExtended;
#else
[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:authenticateLocalPlayerComplete];
#endif
The reason this is important for my app is that it requires Game Center for multi-player. The app tries to authenticate to game center on launch, but if the user cancels we don't ask them at launch again so they won't get nagged. What we do is show a Game Center Login button if they aren't logged in when they select multi-player. The login button forces a game center login by calling authenticateWithCompletionHandler (and now by setting GKLocalPlayer.localPlayer.authenticateHandler again).
Better use runtime checks (instancesRespondToSelector:) instead of preprocessor #if statements, so that you can use recommended methods where they are available and depreciated ones elsewhere. I actually found I need to distinguish three cases before setting the invite handler, as the authentication handler might also get called with a nil view controller:
-(void)authenticateLocalPlayer
{
if ([[GKLocalPlayer class] instancesRespondToSelector:#selector(setAuthenticateHandler:)]) {
[[GKLocalPlayer localPlayer] setAuthenticateHandler:^(UIViewController *gameCenterLoginViewController, NSError *error) {
if (gameCenterLoginViewController) {
[self.presentedViewController presentViewController:gameCenterLoginViewController
animated:YES
completion:^{
[self setInviteHandlerIfAuthenticated];
}];
} else {
[self setInviteHandlerIfAuthenticated];
}
}];
} else { // alternative for iOS < 6
[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error) {
[self setInviteHandlerIfAuthenticated];
}];
}
}
Yet more cases must be distinguished within the invite handler, as matchForInvite:: is new in iOS6 as well and avoids yet another round through game center view controllers:
-(void)setInviteHandlerIfAuthenticated
{
if ([GKLocalPlayer localPlayer].isAuthenticated) {
[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
if (acceptedInvite) {
if ([GKMatchmaker instancesRespondToSelector:#selector(matchForInvite:completionHandler:)]) {
[self showInfoAnimating:YES completion:NULL];
[[GKMatchmaker sharedMatchmaker] matchForInvite:acceptedInvite
completionHandler:^(GKMatch *match, NSError *error) {
// ... handle invited match
}];
} else {
// alternative for iOS < 6
GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithInvite:acceptedInvite] autorelease];
mmvc.matchmakerDelegate = self;
// ... present mmvc appropriately
// ... handle invited match found in delegate method matchmakerViewController:didFindMatch:
}
} else if (playersToInvite) {
// ... handle match initiated through game center
}
};
}
}
Let me know if this helps.
I dont' think this is possible in iOS 6.0. There were API calls to do this in the early SDK builds that were removed before release.
In the WWDC 2012 Video: Session 516 - Integrating Your Games with Game Center [8:30] They actually show code where you call an authenticate method:
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticationHandler = //handle the callback...
[localPlayer authenticate];
This method is now private API but you can see it in action by calling:
[[GKLocalPlayer localPlayer] performSelector:#selector(_authenticate)];
It does exactly what you want, but can't be used because it's now private.
You can also trigger the authentication process by posting the UIApplicationWillEnterForegroundNotification notification:
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication]];
I assume it would be unadvisable to do this in live code.
I am writing an app for iOS 4 that needs to play a sound (or vibrate) at regular (user-specified) intervals when in the background. I do not want to use local notifications because there is no need to have a clickable alert appear.
This code (from Apple's docs) gets triggered when my app switches to the background:
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task.
NSLog(#"I am now in the background");
// Here I need something like this:
[self performSelector:#selector(myMethod) withObject:nil afterDelay:5.0];
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
The [self performSelector: ...] line gets executed when the app is switched to the background, but the myMethod method is not called until the app is switched back to the foreground (not in 5 seconds, as set at the afterDelay: parameter). So, how can I cause the method to be called while the app is still in the background?
Nevermind! Scheduling local notifications can do what I need.
It is better to use local notifications along with UIApplication cancelAllLocalNotifications to clear out existing notifications which the user has not dismissed. Perfect! Plus, the user gets the added benefit if a popup message to let them know what the sound (or vibrate) was for.