Forum Archive

Home Screen alias: is script already running?

jerry

I used “Add to Home Screen” to put a link to my app on my iPad. If I use the link, it starts up the app fine; if I switch to something else, and then hit the link again, it starts up a second (or third, etc.) instance of my app on top of the previous instance.

If I use the X in the upper left corner to close the latest instance, the older instance is underneath, still working.

How can I tell whether or not my app is already running, and not open a new instance but rather just let the existing instance display?

I’ve looked at the list from globals() and don’t see anything obvious there.

mithrendal

I like to know that too. Whenever I launch my ui.View app for example via url schema and it was already running then i have two views stacked on each other. I followed two approaches to solve.

  1. I start a thread and checking every second wether the app is in background. If so then I close the view. This is working but of course with the disadvantage that the view also closes when leaving pythonista for something other then restarting the script a second time.

  2. On start of my script I would try two identify all current views and close them before presenting the new view. But I did not succeed to address e.g. find the views.

JonB

You may be able to check for running instances as follows

import gc, ui
running_views=[v for v in gc.get_objects() if isinstance(v,ui.View) and v.on_screen] 

though the on_screen check won't work for views presented as panels.

omz

You could also just set some flag in a global module when your view is on-screen, and clear it when the view is dismissed. Does this make sense?

mithrendal

SOLVED
I tried a mix of both suggestions with the global variable and the instance and onscreen test. But when I launch the app the second time then the global var is empty.
Now I did the trick with the bultins class. That works fine and solves the issue nicely . Thank you so much.

Here is the code
import builtins

if name == 'main':

try:
    v=builtins.theview
except:
    v=None

if(isinstance(v,ui.View) and v.on_screen ):
    #console.hud_alert('reuse view')
else:
    #console.hud_alert('create view')
    v = ui.load_view()
    v.present('sheet')
    builtins.theview=v
jerry

Thank you! It worked for me, too:

import builtins

try:
    bookView = builtins.navigation
except:
    bookView = None

if bookView and isinstance(bookView, ui.View) and bookView.on_screen:
    print('Reusing existing book view')
    navigation = bookView
    inventoryView = builtins.inventory
    reviewView = builtins.reviews
else:
    reviewView = ui.load_view('views/reviews')
    inventoryView = ui.load_view('views/inventory')
    reviewView.flex = 'WH'
    inventoryView.flex = 'WH'

    if isPhone:
        inventoryView.remove_subview(inventoryView['kinds'])
        titleView = inventoryView['titles']
        titleView.width = inventoryView.width-12

    navigation = StuffView(frame=inventoryView.frame, name='Books & Stuff')
    navigation.add_subview(reviewView)
    navigation.add_subview(inventoryView)
    navigation.present()
    builtins.navigation = navigation
    builtins.inventory = inventoryView
    builtins.reviews = reviewView

ccc

Nice! Can you also see if 'bookView' in locals() or 'bookView' in globals():?

If you do stick with try/except then I would encourage you to avoid a naked exception (see PEP8) because it can hide syntax and other errors that may take precious time to find. In this case except NameError: would be safer than except:.

jerry

Thanks! I’d already checked in locals() and globals() looking for some place where the running view was still accessible; I couldn’t find it. I double-checked again and it still isn’t there.

Capturing only the necessary exception makes sense, but for me I needed to capture AttributeError.

Another thing I tried to do was check that builtins.navigation was an instance of StuffView, my own subclass of ui.View, so as to be even more certain that the saved view I’m finding is the view for this app. But isinstance returned False; I’m assuming this is because the StuffView class was not in locals/globals, and so I had to recreate it; but once recreated, it isn’t the same StuffView that the previous run of Pythonista created navigation from. Whereas it is the same ui.View that each incarnation’s StuffView inherits from.

Here’s my current code to restore my views from a previous run if they exist:

try:
    navigation = builtins.navigation
except AttributeError:
    navigation = None

if navigation and isinstance(navigation, ui.View) and navigation.on_screen:
    reviewView = navigation.subviews[0]
    inventoryView = navigation.subviews[1]
else:
    reviewView = ui.load_view('views/reviews')
    inventoryView = ui.load_view('views/inventory')
    reviewView.flex = 'WH'
    inventoryView.flex = 'WH'

    if isPhone:
        inventoryView.remove_subview(inventoryView['kinds'])
        titleView = inventoryView['titles']
        titleView.width = inventoryView.width-12

    navigation = StuffView(frame=inventoryView.frame, name='Books & Stuff')
    navigation.add_subview(reviewView)
    navigation.add_subview(inventoryView)
    navigation.present()
    builtins.navigation = navigation

One of the things I’m assuming here is that .add_subview will always add subviews in the same order. I couldn’t find any means of getting a subview back by name that wouldn’t have been more work than just saving the subviews on builtins.