Flutter: How to prevent banner ad from showing if view is already disposed - dart

I am currently experimenting with banner ads from the firebase_admob plugin. The process to show and dispose them is pretty straightforward, I do it in initState() and dispose().
The code to create and display the add looks like this:
_bannerAd = createBannerAd();
_bannerAd
..load().then((loaded) {
if (loaded) {
_bannerAd..show();
}
});
However, as I am calling show() asynchronously, it is possible that the view was already closed when the ad is being shown (i.e. by clicking back button really fast). In that case, the dispose() method will never be called and the ad will be "stuck" on the bottom of the screen.
How can I solve this problem? Am I using the banner ad wrong or is it possible to detect if the view was already changed? I tried using the "mounted" property of the state but it didn't seem to work.

Just check "this.mounted" property of state class before showing the add.
_bannerAd = createBannerAd();
_bannerAd
..load().then((loaded) {
if (loaded && this.mounted) {
_bannerAd..show();
}
});

From https://github.com/flutter/flutter/issues/21474#issuecomment-535188820, that's a little hack but it works for me.
You can add a little delay in your dispose method like this:
static void hideBannerAd() {
Future.delayed(Duration(milliseconds: 500), () {
if (_bannerAd != null) _bannerAd.dispose();
_bannerAd = null;
});
}
500 milliseconds is enough.

Related

Update UI rendering in React Natives 'focus' Event Listener

I am navigating from different class objects (screens) within my React Native App. Once I navigate to a given screen, I want to execute different functions including Activity Indicators to show that the function is still running.
Therefore is set up a focus Event Listener which is called every time I navigate back to my screen. My current problem is that my Activity Indicators are not updated within the focus Event but directly after, which is not my wanted behavior as I have to wait for my functions to end without any visual indicator.
class Homescreen extends Component {
constructor(props){
super(props};
this.state = {
showIndicator: false;
}
}
componentDidMount(){
this.props.navigation.addListener('focus', this._onFocus);
}
componentWillUnmount(){
this.props.navigation.removeListener('focus', this._onFocus);
}
_onFocus = async () => {
this.setState({showIndicator: true});
asyncFunc();
};
async asyncFunc(){
//calling a function from swift which calls a C function inside DispatchQeue.main.async
//inside my C function I successfully set my ActivityIndicator to false with an Event which calls
//this.setState({showIndicator: false});
}
render(){
console.log(this.state.showIndicator); // correct value is printed while I wait inside the ```focus``` Event to finish, but the UI is not updated.
return(
{this.state.showIndicator && <ActivityIndicator/>}
)
}
}
I receive the correct current status of showIndicatorbut before the focus Event is not finished, my render does not redraw.
To me it seems like the UI won't update until I am out of my focus Event. How can I reach my goal of displaying the ActivityIndicator before the focus Event or how do I call my function right after the focus Event?
I can achieve my wanted behavior by using the blurevent and setting my ActivityIndicator visible while moving to another screen and after moving back I wait until my function is finished and remove the ActivityIndicator but this seems like a bad workaround and also I can see the ActivityIndicator when moving which might be confusing.
You should replace curly braces around this statement {this.state.showIndicator && } and check.
If it doesn't work accordingly then let me know.

Using Threads to Update UI in Vaadin 14

I created a thread (via a lambda expression) to fetch some data based on user input fields but when I try to click on dropdown menus while it is retrieving data I get the mini progress bar indicator. So is a new thread even being created? What am I doing wrong here?
Button doComputation = new Button("Get Results);
doComputation.addClickListener(event -> {
UI ui = UI.getCurrent();
new Thread(() -> {
// Do some work
ui.access(() -> layout.add(results);
}).start();
});
UPDATE: RESOLVED! Unneccesary ui.access calls were made, which locked up resources. Thank you to all that commented and helped.
The code looks correct to me (apart from the missing end parenthesis after ui.access). Is that the only ui.access call, and is that all you do inside it?
I made this example for reference, and the combo box stays responsive while the background task is running.
#Route
public class ThreadView extends VerticalLayout {
public ThreadView() {
Button runThreadButton = new Button("Start thread", e -> {
UI ui = UI.getCurrent();
new Thread(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
ui.access(() -> Notification.show("Completed"));
}).start();
});
ComboBox<String> comboBox = new ComboBox<>("Items", "One", "Two", "Three");
add(runThreadButton, comboBox);
}
}
So is a new thread even being created?
You can verify that by adding a System.out.println("Thread started") and checking whether that message is printed, or by running your application in debug mode and setting a breakpoint on the part that you're interested in.
What am I doing wrong here?
The code that you showed looks fine. I would guess there's a problem outside the shown code, namely that you have forgotten that you also need to add the #Push annotation. Without that annotation, the server will have no way of directly sending messages to the client.

ICommand not always firing when tab selected

I have a simple ActionBar with 3 tabs attached. When a tab is clicked, the fragment is inflated and the view shows. The tab being click event is fired using an event. Initially, the first fragment is inflated, but the others respond and inflate if clicked.
If I change the event being fired to an ICommand, only the last fragment is inflated and then if I click on the first tab, that and the last are inflated. Never the second.
My code is this
ICommand TabClicked
{
get
{
return new RelayCommand(() =>
{
tab.TabSelected += (object sender, ActionBar.TabEventArgs e) => TabOnTabSelected(sender, e);
});
}
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
fragments.Add(new TODFragment());
fragments.Add(new ConditionsFragment());
fragments.Add(new ResultsFragment());
AddTabToActionBar("Time", Resource.Drawable.crucifix_colour);
AddTabToActionBar("Conditions", Resource.Drawable.weather_colour);
AddTabToActionBar("Results", Resource.Drawable.tod_colour);
}
void AddTabToActionBar(string text, int iconResourceId)
{
tab = ActionBar.NewTab().SetTag(text).SetText(text).SetIcon(iconResourceId);
/* uncomment and comment out one of the two below to see the difference in operation */
tab.TabSelected += TabOnTabSelected;
//tab.SetCommand<ActionBar.TabEventArgs>("TabSelected", TabClicked);
ActionBar.AddTab(tab);
}
void TabOnTabSelected(object sender, ActionBar.TabEventArgs tabEventArgs)
{
var tabNo = sender as ActionBar.Tab;
var frag = fragments[tabNo.Position];
tabEventArgs.FragmentTransaction.Replace(Resource.Id.frameLayout1, frag);
}
Am I missing something fundamental here in the difference between ICommands and Events or is it something else?
I'm using Xam.Android and MVVMLight
I found the answer. When I create the partial class I define the UI objects like this (or something like this at least)
EditText myEditText;
EditText MyEditText = myEditText ?? (view.FindViewById<EditText>(Resources.Id.myEdit);
This is fine, but it does mean that once defined, it doesn't get redefined.
Not a problem if the UI is not really going to change, but every time an action tab is pressed, the fragment is refreshed. Only problem is the Id isn't changing as myEditText is not null.
The answer is add a method in the UI definition code that nulls the objects then in the main code, when the UI disappears, call the nulling method. Everything works then

Monotouch.Dialog - How to push a view from an Element

It seems like this should be very easy, but I'm missing something. I have a custom Element:
public class PostSummaryElement:StyledMultilineElement,IElementSizing
When the element's accessory is clicked on, I want to push a view onto the stack. I.e. something like this:
this.AccessoryTapped += () => {
Console.WriteLine ("Tapped");
if (MyParent != null) {
MyParent.PresentViewController(new MyDemoController("Details"),false,null);
}
};
Where MyDemoController's gui is created with monotouch.dialog.
I'm just trying to break up the gui into Views and Controlls, where a control can push a view onto the stack, wiat for something to happen, and then the user navigates back to the previous view wich contains the control.
Any thought?
Thanks.
I'd recommend you not to hardcode behavior in AccessoryTapped method, because the day when you'll want to use that component in another place of your project is very close. And probably in nearest future you'll need some another behavior or for example it will be another project without MyDemoController at all.
So I propose you to create the following property:
public Action accessoryTapped;
in your element and its view, and then modify your AccessoryTapped is that way:
this.AccessoryTapped += () => {
Console.WriteLine ("Tapped");
if (accessoryTapped != null) {
accessoryTapped();
}
};
So you'll need to create PostSummaryElement objects in following way:
var myElement = new PostSummaryElement() {
accessoryTapped = someFunction,
}
...
void someFunction()
{
NavigationController.PushViewController (new MyDemoController("Details"), true);
}

Blocking/disabling JavaFX 2 WebView right click

I'm looking for a way to block/disable right click in javafx.scene.web.WebView. To be more specific I don't want the context menu to show up on right click. I'm new to the technology and can't find the way to do it.
Just for the record, it is implemented in JavaFX 2.2. See documentation for setContextMenuEnabled (JavaFX 2) and setContextMenuEnabled (JavaFX 8)
I've came up with working, but ugly, inelegant and, I'd say, partisan solution, which I don't really like, but actually I have no (or just can't find) other way out.
It includes modifying EventDispatcher of WebView.
So my implementation of EventDispatcher needs a reference to original WebView EventDispatcher and looks like that:
public class MyEventDispatcher implements EventDispatcher {
private EventDispatcher originalDispatcher;
public MyEventDispatcher(EventDispatcher originalDispatcher) {
this.originalDispatcher = originalDispatcher;
}
#Override
public Event dispatchEvent(Event event, EventDispatchChain tail) {
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
if (MouseButton.SECONDARY == mouseEvent.getButton()) {
mouseEvent.consume();
}
}
return originalDispatcher.dispatchEvent(event, tail);
}
}
Everytime event is dispatched it goes through our dispatcher and I check if it's right click. If it is I just consume it and proceed further.
To make it work you have to use WebView like that:
WebView webView = new WebView();
EventDispatcher originalDispatcher = webView.getEventDispatcher();
webView.setEventDispatcher(new MyEventDispatcher(originalDispatcher));
Every comment, clue and so on are appreciated.
With JavaFX 2.2+ it's now possible to set WebView's ContextMenuEnabled to false:
webView.setContextMenuEnabled(false);
WebView API Doc.
You can style context menus away using the following css.
.context-menu { -fx-background-color: transparent; }
.menu-item { -fx-background-color: transparent; }
.menu-item .label { -fx-text-fill: transparent; }
.menu-item:show-mnemonics .mnemonic-underline { -fx-stroke: -transparent; }
This will make all context menus and menu items transparent. I'm not sure of the css selector you could use to make this only apply to WebView context menus. If you don't have other menus in your application, that may not be a big deal.
You can do it with js (jquery used)
$(document).ready( function() { document.oncontextmenu = function() { return false } } );
Unfortunately it's not yet possible. There is a feature request for that, which you may want to track: http://javafx-jira.kenai.com/browse/RT-15684
This will will remove the context menu for the entire stage:
primaryStage.getScene().addEventFilter(MouseEvent.MOUSE_RELEASED,
new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
if (event.getButton() == MouseButton.SECONDARY) {
event.consume();
}
}
});

Resources