Is there a better way to enforce singleton behavior in AppDesigner applications?
3 views (last 30 days)
When you click "Run" from inside the App Designer window, any existing instance of that app will be closed before a new one is created. However, if you create instances of the application from anywhere else, you can get multiple copies running at the same time.
I'd like to be able to have instances created both inside and outside the AppDesigner window to behave consistently.
I found a hacky workaround, and would like to know if someone has a better approach.
(As an aside, I believe the ability to get multiple instances running at the same time is broken behavior, because the internal AppManagementService class used to register and manage running applications uses a containers.Map() to associate mlapp filenames with running instances. However, this map only allows for one instance to be associated with each filename key, so you may have more than one instance running, but only one will be properly registered on the backend.)
Right now, the App Designer enfornces singleton behavior, but the actual application class does not, because the constructor is public. You also cannot modify the attributes of the constructor in AppDesigner, and by the time the application's startupFcn() has been called, the internal management map has already been updated. This means you cannot enforce the singleton behavior outside the AppDesigner.
Here's the workaround I came up with. This code goes into the mlapp's startupFcn() callback, and seems to mimic the behavior of App Designer.
% Code that executes after component creation
% Find all the figures that might be related to instances of
% this application.
figures = findall(groot, '-depth', 1, 'Type', 'Figure');
% Shutdown all other instances of this app.
for k = 1:numel(figures)
fig = figures(k);
% Only consider valid figures with a 'RunningAppInstance'
% property, because this is the sign that the figure is
% from an AppDesigner app.
if isvalid(fig) && isprop(fig, 'RunningAppInstance')
other = fig.RunningAppInstance;
% Make sure the figure's app as the same class as us,
% and also make sure we don't delete ourself.
if isa(other, class(app)) && ~isequal(app, other)
% Delete the other instance. This automatically
% closes the associated figure as well.
This seems like a hack. I would love to know if there's a better way to achieve the pseudo-singleton behavior that App Designer enforces with the run button.