Flutter - Admob - Display banner just on one page - firebase

I want to display my adBanner only on one page, nothing else.
Currently, when I click on my page and I go back instantly, my ad loaded, and displayed on my main page.
I partialy fix this with:
Second screen
#override
void initState() {
super.initState();
FirebaseAdMobService().showBannerAd();
}
#override
dispose() async {
FirebaseAdMobService().hideBannerAd();
super.dispose();
}
AdmobService
import 'package:firebase_admob/firebase_admob.dart';
import 'package:flutter/foundation.dart';
class FirebaseAdMobService {
static final FirebaseAdMobService _singleton = FirebaseAdMobService._internal();
FirebaseAdMobService._internal();
factory FirebaseAdMobService() {
return _singleton;
}
BannerAd _adBanner;
bool _hide = false;
init() async {
await FirebaseAdMob.instance.initialize(appId: "...");
}
static const MobileAdTargetingInfo targetingInfo = MobileAdTargetingInfo(
keywords: <String>['foo', 'bar'],
childDirected: true,
nonPersonalizedAds: true,
);
BannerAd _createBannerAd() {
return BannerAd(
adUnitId: kReleaseMode ? "..." : BannerAd.testAdUnitId,
size: AdSize.banner,
targetingInfo: targetingInfo,
listener: (MobileAdEvent event) {
print("BannerAd event $event");
},
);
}
void showBannerAd() {
_hide = false;
Future.delayed(const Duration(seconds: 2), () {
if (_hide) {
return;
}
if (_adBanner == null) {
_adBanner = _createBannerAd();
}
_adBanner.load().then((loaded) {
_adBanner.show(anchorType: AnchorType.bottom);
_hide = false;
});
});
}
void hideBannerAd() async {
_hide = true;
await _adBanner?.dispose();
_adBanner = null;
}
}
With this, my ad is displayed after 2 seconds, but if you time the ad display (press back just after 2 seconds), the ad will displayed on the main page... and with my UI, block my bottom tab control.
How to prevent my ad from appearing elsewhere than on my second screen?
Thanks

Related

MainPage fails to Load properly

I have this code to set the Mainpage of my Application.
public async Task LoadMainPage()
{
try
{
signedin = Auth.IsUserSignedIn();
if (signedin)
registered = await Firestore.IsUserRegistered();
if (!signedin)
{
MainPage = new NavigationPage(new MainPage());
}
else if (signedin && !(registered))
{
MainPage = new NavigationPage(new RegistrationPage());
}
else if (signedin && (registered))
{
MainPage = new NavigationPage(new FlyoutPage1());
}
}
catch (Exception ex) { await App.Current.MainPage.DisplayAlert("Error", ex.Message, "OK"); }
}
I am calling this method from App.Xaml.cs Onstart method
protected override async void OnStart()
{
base.OnStart();
await LoadMainPage();
}
the problem is when the Application is launched the Mainpage fails to Load Properly.
it appears only when i tap the triple line icon on my phone wait for some time and tap the application again to launch it.
the code for Firestore.IsUserRegistered is as below
public async Task<bool> IsUserRegistered()
{
FirebaseFirestore collection = FirebaseFirestore.Instance;
string email = FirebaseAuth.Instance.CurrentUser.Email;
Android.Gms.Tasks.Task task = collection.Collection("User").WhereEqualTo("Email", email)
.Limit(1).Get().AddOnSuccessListener(this);
for (int i = 0; i < 25; i++)
{
await Task.Delay(100);
if (isregistered ) break;
}
return isregistered;
}
public void OnSuccess(Java.Lang.Object result)
{
var documents = (QuerySnapshot)result;
isregistered = !documents.IsEmpty;
}
You can add await LoadMainPage(); to OnResume() just like Splash Screen.
It said:
The startup work is performed asynchronously in OnResume. This is necessary so that the startup work does not slow down or delay the appearance of the launch screen. When the work has completed, SplashActivity will launch MainActivity and the user may begin interacting with the app.

can not show alertcontroller when page is displayed using PushModalAsync

I am trying to show toast message in android and iOS from xamarin.forms project using Dependency Service. In iOS project message is shown on MainPage or NavigationPage. but when I navigate a second page on button click using PushModalAsync, message is not displayed.
How I navigate the page
public LoginPage()
{
Device.BeginInvokeOnMainThread(() =>
{
CustomToast.LongMessage("Hiiiiii"); // Message shown
});
Navigation.PushModalAsync(new RegisterPage()); //Doesn't show
//var reg = new RegisterPage();
//Application.Current.MainPage = reg; // toast shown here
}
Code for alertController in iOS :
const double SHORT_DELAY = 2.0;
NSTimer alertDelay;
UIAlertController alert;
public void LongAlert(string message)
{
ShowAlert(message, LONG_DELAY);
}
public void ShortAlert(string message)
{
ShowAlert(message, SHORT_DELAY);
}
void ShowAlert(string message, double seconds)
{
try
{
if (alert == null && alertDelay == null)
{
alertDelay = NSTimer.CreateScheduledTimer(seconds, (obj) =>
{
Device.BeginInvokeOnMainThread(() =>
{
DismissMessage();
});
});
Device.BeginInvokeOnMainThread(() =>
{
try
{
alert = UIAlertController.Create("", message, UIAlertControllerStyle.ActionSheet);
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alert, true, null);
}
catch (Exception ex)
{
var Error = ex.Message;
}
});
}
}
catch (Exception ex)
{
TraceLog("Message iOS ShowAlert : " + ex.Message);
}
}
void DismissMessage()
{
if (alert != null)
{
alert.DismissViewController(true, null);
alert = null;
}
if (alertDelay != null)
{
alertDelay.Dispose();
alertDelay = null;
}
}
And I call this from my register page constructor
Device.BeginInvokeOnMainThread(() =>
{
CustomToast.LongMessage("Hiiiiii");
});
It doesn't go in catch anywhere but its not displayed also. can anyone please suggest some advice ?
This is because RegisterPage is a presented page on your LoginPage, UIApplication.SharedApplication.KeyWindow.RootViewController this code can't retrieve a correct view controller for RegisterPage. It just presented an action sheet on the previous page, but your app has reached a new page then this Toast can be shown on the screen.
Firstly, you have to find out the top page on the window:
UIViewController topViewControllerWithRootViewController(UIViewController rootViewController)
{
if (rootViewController is UITabBarController)
{
UITabBarController tabBarController = (UITabBarController)rootViewController;
return topViewControllerWithRootViewController(tabBarController.SelectedViewController);
}
else if (rootViewController is UINavigationController)
{
UINavigationController navigationController = (UINavigationController)rootViewController;
return topViewControllerWithRootViewController(navigationController.VisibleViewController);
}
else if (rootViewController.PresentedViewController != null)
{
UIViewController presentedViewController = rootViewController.PresentedViewController;
return topViewControllerWithRootViewController(presentedViewController);
}
return rootViewController;
}
Secondly, adjust your presenting code like:
Device.BeginInvokeOnMainThread(() =>
{
try
{
alert = UIAlertController.Create("", messages, UIAlertControllerStyle.ActionSheet);
topViewControllerWithRootViewController(UIApplication.SharedApplication.KeyWindow.RootViewController).PresentViewController(alert, true, null);
}
catch (Exception ex)
{
var Error = ex.Message;
}
});
At last, you could show your toast using Navigation.PushModalAsync(new RegisterPage());

Calling Async task in button click in xamarin.forms

I have xamarin.forms app contains a listview which will load values from Rest API.Which is working fine.I have button just above the listview.When I click on the button, the listview API call will be placed again and the listview should update. But stuck at this update part.I am not using MVVM pattern.The listview listing portion is an async Task.I am calling the async task again when the button click, but App gets crash. Is it due to calling the async task again from button click? Any help is appreciated.
Here is My code.
namespace app
{
public partial class List : ContentPage
{
PendingWeekRange pendingWeekRange = new PendingWeekRange();
public TimeSheetList()
{
InitializeComponent();
Task.Run(async () =>
{
await LoadScreenItems();
});
}
async Task LoadScreenItems()
{
await Task.Run(async () => {
try
{
// Doing some stuff
await loadTimeSheetList();
}
catch (Exception)
{
}
});
}
async Task loadTimeSheetList()
{
await Task.Run(() => { + string postdataForPendingList = "{\"date\":\"" + "1" + "\"}";
APICall callForAPICallResult = new APICall("/API/ListMobile/ListForApproval", postdataForList, loadingIndicator);
try
{
List<ListData> resultObjForPendingTimeSheetList = callForAPICallResult<List<ListData>>();
if (resultObjForPendingTimeSheetList != null)
{
TimesheetList.ItemsSource = resultObjForPendingTimeSheetList;
screenStackLayout.VerticalOptions = LayoutOptions.FillAndExpand;
TimesheetList.IsVisible = true;
}
else
{
}
}
catch (Exception)
{
}
});
}
async void Button_Tapped(object sender, EventArgs e)
{
try
{
// Calling my listview again. After calling app gets crash
Task.Run(async () => await loadTimeSheetList());
}
catch (Exception ex) { }
}
}
}
A few things before getting to the problem. You've got async/await all wrong, go though Async Programming
Task.Run runs the passed action on a different thread, if you make changes to UI elements on this thread, your app will definitely(take my word) crash.
If you want to make async call at page launch, make use of OnAppearing method (if you only want to call once, maintain a flag)
Do not change the ItemsSource of a list view frequently, just clear and add items to it.
namespace app
{
public partial class List : ContentPage
{
PendingWeekRange pendingWeekRange = new PendingWeekRange();
private ObservableCollection<ListData> TimesheetObservableCollection = new ObservableCollection<ListData>();
public TimeSheetList()
{
InitializeComponent();
TimesheetList.ItemsSource = TimesheetObservableCollection;
}
protected override async OnAppearing()
{
// flag for first launch?
await LoadScreenItems();
}
async Task LoadScreenItems()
{
try
{
// Doing some stuff
TimesheetObservableCollection.Clear();
TimesheetObservableCollection.AddRange(await GetTimeSheetList());
}
catch (Exception)
{
//handle exception
}
}
async Task<List<ListData>> GetTimeSheetList()
{
string postdataForPendingList = "{\"date\":\"" + "1" + "\"}";
APICall callForAPICallResult = new APICall("/API/ListMobile/ListForApproval", postdataForList, loadingIndicator);
try
{
return callForAPICallResult<List<ListData>>();
}
catch (Exception)
{
// handle exception
}
}
async void Button_Tapped(object sender, EventArgs e)
{
try
{
// Calling my listview again. After calling app gets crash
TimesheetObservableCollection.Clear();
TimesheetObservableCollection.AddRange(await GetTimeSheetList());
}
catch (Exception ex) { }
}
}
}
#Androdevil,
Update your loadTimeSheetList with this,
async Task loadTimeSheetList()
{
try
{
// I am calling my API for Listview here.
List<TimeSheetListData> resultObjForPendingTimeSheetList = await callForPendingTimeSheetList.APICallResult<List<TimeSheetListData>>();
if (resultObjForPendingTimeSheetList != null)
{
TimesheetList.ItemsSource = resultObjForPendingTimeSheetList;
screenStackLayout.VerticalOptions = LayoutOptions.FillAndExpand;
TimesheetList.IsVisible = true;
}
else
{
}
}
catch (Exception)
{
}
}

How to keep changing a Images every 5 seconds in Flutter?

State Variables :
var moviePhotos = [
"http://www.kiwithebeauty.com/wp-content/uploads/2017/11/BLACK-PANTHER-COLLAGE-KIWI-THE-BEAUTY-MOVIE-MARVEL-800x350.png",
"https://static-ssl.businessinsider.com/image/5a7085a97e7a35f10c8b479f-1000/blackpanthershuri.jpg",
"https://longreadsblog.files.wordpress.com/2018/02/black-panther.jpg?w=1680",
"https://uziiw38pmyg1ai60732c4011-wpengine.netdna-ssl.com/wp-content/dropzone/2018/02/black-panther.jpg",
"https://static2.srcdn.com/wp-content/uploads/2017/10/Black-Panther-Trailer-1.jpg?q=50&w=1000&h=500&fit=crop&dpr=1.5",
"https://cdn.guidingtech.com/imager/media/assets/BP-2_acdb3e4bb37d0e3bcc26c97591d3dd6b.jpg",
"https://cdn.guidingtech.com/imager/media/assets/BP-8_acdb3e4bb37d0e3bcc26c97591d3dd6b.jpg"
];
var bannerPosition = 0;
I want the below function to change the position in the array every 5 seconds by incrementation bannerPosition so that a new image renders on the app
testing() async {
while(true){
await new Future.delayed(const Duration(seconds : 5));
if (bannerPosition < moviePhotos.length){
print("Banner Position Pre");
print(bannerPosition);
setState(() {
bannerPosition = bannerPosition + 1;
});
print("Banner Position Post");
print(bannerPosition);
}
else{
setState(() {
bannerPosition = 0;
});
}
}
}
The "Future.delayed(const Duration(seconds : 5))" does not occur in an orderly fashion when I execute this code and it results in image rendering issues.
I don't know what you mean by 'does not occur in an orderly fashion'. While just looking at that I'd think it would work, except that I seem to remember there being something weird about using await in a loop. It might keep looping around and creating more and more calls to the delayed....
Instead, use a Timer. That way it handles the looping. I'd also advise saving a reference to the timer and stopping it in your state's dispose() function.
Here's a code example:
class ImageRotater extends StatefulWidget {
List<String> photos;
ImageRotater(this.photos);
#override
State<StatefulWidget> createState() => new ImageRotaterState();
}
class ImageRotaterState extends State<ImageRotater> {
int _pos = 0;
Timer _timer;
#override
void initState() {
_timer = Timer.periodic(new Duration(seconds: 5), () {
setState(() {
_pos = (_pos + 1) % widget.photos.length;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return new Image.network(
widget.photos[_pos],
gaplessPlayback: true,
);
}
#override
void dispose() {
_timer.cancel();
_timer = null;
super.dispose();
}
}
Note that there still might be some inconsistency the first time it goes through the photos because it is just loading them as it goes. The 'gaplessPlayback' flag should make the previous image stick around until the new one is fully loaded.
Improving on "rmtmckenzie" answer, you need to use Timer.periodic if you want to repeat this every 5 seconds. See below
#override
void initState() {
_timer = Timer.periodic(Duration(seconds: 5), (Timer t) {
setState(() {
_pos = (_pos + 1) % widget.photos.length;
});
});
super.initState();
}

How to initialize bar code scanner on App startup

I have a requirement for my xamarin cross platform application that as soon as app start up .QR Scanner set in to read the code. on completing scanning a beep will be ring up.and app again ready for next scanning how can i get this done. what i have done is on button click scanner start, its read code, then i have to press button again to start it again.
public HomePage()
{
Button scanBtn = new Button
{
Text = "Scan Barcode",
HorizontalOptions = LayoutOptions.FillAndExpand,
};
scanBtn.Clicked += async (sender, args) =>
{
var scanResult = await Acr.BarCodes.BarCodes.Instance.Read();
if (!scanResult.Success)
{
await this.DisplayAlert("Alert ! ", "Sorry ! \n Failed to read the Barcode !", "OK");
}
else
{
var endpoint = new EndpointAddress("http://192.168.15.33/SMS/WebServices/SMSService.svc");
var binding = new BasicHttpBinding
{
Name = "basicHttpBinding",
MaxBufferSize = 2147483647,
MaxReceivedMessageSize = 2147483647
};
TimeSpan timeout = new TimeSpan(0, 0, 30);
binding.SendTimeout = timeout;
binding.OpenTimeout = timeout;
binding.ReceiveTimeout = timeout;
_client = new SMSServiceClient(binding, endpoint);
_client.ValidateStudentAsync("123-admin");
_client.ValidateStudentCompleted += _client_ValidateStudentCompleted; ;
// await this.DisplayAlert("Scan Successful !", String.Format("Barcode Format : {0} \n Barcode Value : {1}", scanResult.Format, scanResult.Code), "OK");
}
};
Content = new StackLayout
{
Children = {
scanBtn
}
};
}
and in app.cs
public class App : Application
{
public App()
{
// The root page of your application
MainPage = new HomePage();
}
protected override void OnStart()
{
MainPage = new HomePage();
}
protected override void OnSleep()
{
MainPage = new HomePage();
}
protected override void OnResume()
{
MainPage = new HomePage();
}
}
You can use ZXing.Net.Mobile for Forms to read QR codes. To initialize this plugin you should call method to init into each project (Android, iOS, UWP) like this:
For Android in MainActivity.cs class call:
ZXing.Net.Mobile.Forms.Droid.Platform.Init();
For iOS in AppDeletage.cs class call
ZXing.Net.Mobile.Forms.iOS.Platform.Init();
And finally to read QR Codes:
private async void Scan() {
var scanPage = new ZXingScannerPage();
scanPage.OnScanResult += (result) => {
// Stop scanning
scanPage.IsScanning = false;
// Pop the page and show the result
Device.BeginInvokeOnMainThread( async () => {
await Navigation.PopAsync();
await DisplayAlert("Scanned Barcode", result.Text, "OK");
});
};
// Navigate to our scanner page
await Navigation.PushAsync(scanPage);
}

Resources