Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Show Posts

* | |

  Show Posts
Pages: [1] 2 3
1  PureMVC Manifold / Multicore Version / Component architecture - Where to Start? on: November 05, 2012, 09:08:37
I'm working out a responsive design template that may be useful for others.  Showing / hiding of things like top nav and bottom nav is done programmatically, side menu, all that.

How would I begin thinking of this as a puremvc plugin?  I've created many jQuery plugins, so I'm familiar with this format, but a puremvc approach would be different.  I'm trolling for best practices, I guess, since a plugin architecture would open some doors.

Thanks in advance.
2  PureMVC Manifold / Multicore Version / Using JS-Signals with View Components on: September 21, 2012, 11:03:54
I wanted to post this because I'm having a lot of luck with JS-Signals http://millermedeiros.github.com/js-signals/ in the Views and Mediators of a jQuery-based application, specifically around the area of handling user interaction from viewComponent.  Obviously there are alternatives, but this one is turning out to be fairly clean and straightforward.

I'm using:

I'm instantiating a new view component on the Mediator's on Register, and calling setViewComponent(). 

:
/**
 * @author Mike Britton
 *
 * @class ScrollerMediator
 *
 *
 *
 */

puremvc.define({
    name : 'rps.view.mediator.ScrollerMediator',
    parent : puremvc.Mediator
},
// INSTANCE MEMBERS
{
    /** @override */
    listNotificationInterests : function() {
        return [rps.AppConstants.NOTE_PAGES_RETRIEVED,rps.AppConstants.NOTE_APP_RESIZE];
    },
    /** @override */
    onRegister : function() {
       
        // Create the viewComponent
        this.setViewComponent(new rps.view.component.ScrollerComponent);
       
        // Establish signal listeners
        this.doSignals();
       
    },
    /** @override */
    handleNotification : function(note) {
        //console.log('ScrollerMediator::handleNotification - ' + note.getName());

        switch (note.getName()) {
            case rps.AppConstants.NOTE_APP_RESIZE:
                this.getViewComponent().updateUI(note.getBody());
                this.doSignals();
                break;
            case rps.AppConstants.NOTE_PAGES_RETRIEVED:
                this.getViewComponent().build(note.getBody());
                break;
        }
    },
    doSignals:function(){
        var target = this;
        $.each(this.getViewComponent().signals, function(index, item) {
           if (!item.has(target.handleEvent)) {
               // Second arg is scope
               item.add(target.handleEvent, target);
           }
        });     
    },
    handleEvent : function(signal) {
       switch(signal){
           case rps.view.component.ScrollerComponent.SIGNAL_READY:
              //console.log('ScrollerMediator::Signal '+signal+' received');
           break;
       };

    }
},
// STATIC MEMBERS
{
    /**
     * @static
     * @type {string}
     */
    NAME : 'ScrollerMediator'
});

Inside the view component, I call build() and use underscore.js to retrieve templates:

:
var comp = _.template($('#stripsTmpl').html());

An underscore template looks like this in HTML:

:
<script type="text/template" id="stripsTmpl">
    <div id="pagesX" class="pagesX" style="width:<%- pagesXWidth %>px;height:<%- pagesXHeight %>px;"></div>
    <div id="pagesY" style="position:absolute;width:<%- pagesYWidth %>px;height:<%- pagesYHeight %>px;"></div>
</script>

Back in my component class, I have public signals[], each key being a new signals.Signal(). In my Mediator, I call doSignals() once the viewComponent has been created, and set a single handler (see above) for all signals.  All user interactions in the viewComponent dispatch Signals back to the Mediator's handleEvent().

Scope issues between viewComponent and Mediator are handled with a Signals context argument:

:
doSignals:function(){
    var target = this;
    $.each(this.getViewComponent().signals, function(index, item) {
       if (!item.has(target.handleEvent)) {
           // Second arg is scope
           item.add(target.handleEvent, target);
       }
    });     
},

Why use Signals?  I don't want to troubleshoot native events until their implementation stabilizes across browsers and platforms.  (At least not for client projects.)  I want to abstract them, to keep my architecture safe from contamination by proprietary hocus-pocus with respect to event programming.  Not sure if this is the right approach, but it feels right.

Hope this proves useful, either directly or as an example of how not to do it!   ;D


Mike
3  PureMVC Manifold / Multicore Version / Re: puremvc with requirejs and or nodejs. on: September 21, 2012, 10:26:04
Indeed, very helpful.  Props all around.
4  PureMVC Manifold / Multicore Version / Registering and retrieving a proxy on: January 21, 2012, 01:34:42
Can't seem to retrieve my proxy once I've registered it:

:
var facade = Facade.getInstance('ApplicationFacade');
   
 facade.registerProxy(new StoryProxy(StoryProxy.NAME, []));

Then elsewhere, after StroyProxy's onRegister fires:

:
var prox = facade.retrieveProxy(StoryProxy.NAME);
console.dir(prox); // undefined

My proxy (probably where the problem is):

:
function StoryProxy(name, component) {
    console.log('new StoryProxy: '+name);
    Proxy.call(name);
}

StoryProxy.prototype = new Proxy;
StoryProxy.prototype.constructor = StoryProxy;

StoryProxy.NAME = 'StoryProxy';

/** @override */
StoryProxy.prototype.initializeNotifier = function() {
    console.log('StoryProxy::initializeNotifier'); 
};
StoryProxy.prototype.onRegister = function() {
    console.log('StoryProxy::onRegister'); 
    var facade = Facade.getInstance('ApplicationFacade');
    facade.sendNotification(Application.NOTE_GET_STORIES);
};

Thanks in advance!
5  PureMVC Manifold / Standard Version / Re: Flex Mobile ViewNavigator and PureMVC on: June 12, 2011, 04:41:33
#2 is the way I chose to deal with it.  I wanted to centralize this with a Command and a Notification for all removal / instantiation.

It feels laborious to remove / instantiate new Mediators every time a view is pushed, so my next step is to encapsulate it somehow.  A plugin?  Dunno yet...

I stopped there, when I had a decent boilerplate to use for projects, then went and did the same thing for the Java port.
6  PureMVC Manifold / MultiCore Version / Re: Android: Activity Management in PureMVC on: April 08, 2011, 01:01:04
A value object contains the name of the next page.  A new Activity (coincidentally named "SubPage") is instantiated and replaces the old one (the page changes).
7  PureMVC Manifold / MultiCore Version / Re: Android: Activity Management in PureMVC on: April 07, 2011, 03:05:47
I was playing around with centralizing Activity management in a Command.  Again, not sure if this is best practice but "it works"  :-\.

Button is pressed on an Activity (handler below):

:
private void initDisplay() {
btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
observable.setChanged();

//  Custom event is assigned a page vo
InteractionEvent evt = new InteractionEvent(this);
PageChangeVO vo = new PageChangeVO();

// page vo's newPageName variable is set
vo.newPageName = ActivityNames.SUB_PAGE;
evt.pageVO = vo;

observable.notifyObservers( evt );
observable.clearChanged();
}
});
}

Observer (Mediator) receives update from its Activity and sets the activity variable on the VO:

:
@Override
public void update(Observable arg0, Object arg1) {
Log.d(TAG, "UPDATE");
InteractionEvent evt = (InteractionEvent) arg1;
evt.pageVO.activity = this.getApplication();

this.sendNotification(NotificationNames.CHANGE_PAGE, evt);
}

ChangePageCommand is executed:

:
@Override
public void execute(INotification notification) {
super.execute(notification);

Log.d(TAG, TAG+"::execute");

String mediatorName;
InteractionEvent evt = (InteractionEvent) notification.getBody();
Activity act = (Activity) evt.pageVO.activity;
Activity newAct;
Mediator newMediator = null;
Intent intent = null;

// Remove the Mediator of the Activity doing the page change

if (act.getClass().getName().equalsIgnoreCase(ActivityNames.APPLICATION) ) {
mediatorName = MediatorNames.APPLICATION_ACTIVITY;
if (getFacade().hasMediator(MediatorNames.APPLICATION_ACTIVITY)) {
getFacade().removeMediator(MediatorNames.APPLICATION_ACTIVITY);
}
}

if (act.getClass().getName().equalsIgnoreCase(ActivityNames.SUB_PAGE) ) {
mediatorName = MediatorNames.SUB_PAGE_ACTIVITY;
if (getFacade().hasMediator(MediatorNames.SUB_PAGE_ACTIVITY)) {
getFacade().removeMediator(MediatorNames.SUB_PAGE_ACTIVITY);
}
}

// Instantiate the new Activity

if (evt.pageVO.newPageName == ActivityNames.APPLICATION) {
newAct = new ApplicationActivity();
newMediator = new ApplicationMediator(MediatorNames.APPLICATION_ACTIVITY, (ApplicationActivity)newAct);
intent = new Intent(act, ApplicationActivity.class);
}

if (evt.pageVO.newPageName == ActivityNames.SUB_PAGE) {
newAct = new SubPageActivity();
newMediator = new SubPageMediator(MediatorNames.SUB_PAGE_ACTIVITY, (SubPageActivity)newAct);
intent = new Intent(act, SubPageActivity.class);
}

getFacade().registerMediator(newMediator);

act.startActivity(intent);

act.finish();
}

Again, just playing around.  Thoughts?


Mike


8  PureMVC Manifold / MultiCore Version / Android: Activity Management in PureMVC on: April 06, 2011, 12:58:24
I may be barking up the wrong tree again, but it seems like managing views (Activities) from inside other Activities is bad.  How do I know which Activity is changing the page with an Intent?

Just for the hell of it, I implemented it in a Command.  Now I don't have to wonder which Activity did what; it's all centralized.  Granted it will have to have a case for each page in the application, but I see less scalability issues than with dispatching Intents inside Activities that should have no knowledge or control of them, in theory.
9  PureMVC Manifold / MultiCore Version / Android: Events on: April 05, 2011, 01:02:38


When trying to figure out how to send events from Activities to Mediators, I first created interface InteractionListener for the Mediator to implement:

:
package com.britton.apps.puremvcboilerplate.view;

import com.britton.apps.puremvcboilerplate.view.event.InteractionEvent;

public interface InteractionListener {
public void interactionReceived(InteractionEvent event);
public void configureListeners(InteractionListener m);
}


Implementation in Mediator:

:
@Override
public void onRegister() {
super.onRegister();
configureListeners(this);
}

@Override
public void configureListeners(InteractionListener m) {
this.getApplication().addListener(m);
}

@Override
public void interactionReceived(InteractionEvent event) {
Log.d(TAG, "Event Received");
}


In my experimental app, Activity is subclassed as InteractionActivity (which could also be an abstract class):

:
package com.britton.apps.puremvcboilerplate.view;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;

public class InteractionEmitterActivity extends Activity {
public List listeners;

public InteractionEmitterActivity() {
listeners = new ArrayList();
}

public synchronized void addListener(InteractionListener il) {
        listeners.add(il);
    }

    public synchronized void removeListener(InteractionListener il) {
        listeners.remove(il);
    }
}


And in ApplicationActivity, the subclass, where there's a Button ready to trigger this miraculous handler:

:
private void initDisplay() {
btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {
InteractionEvent ie = new InteractionEvent(this);
Iterator it = listeners.iterator();

while (it.hasNext()) {
InteractionListener il = (InteractionListener) it.next();
il.interactionReceived(ie);
}
}
});
}


So now, any Activity that extends InteractionEmitterActivity can, by contract, send InteractionEvents to the Mediator actor.

Here's the InteractionEvent:

:
package com.britton.apps.puremvcboilerplate.view.event;

import java.util.EventObject;

public class InteractionEvent extends EventObject {

public InteractionEvent(Object source) {
super(source);
}
}

I realize this is very Flex-like; in fact, I kept thinking about Signals when I wrote it!  I've had success with them.  Maybe that's another route.


Mike
10  PureMVC Manifold / Standard Version / Re: android on: March 29, 2011, 11:03:25
I definitely get the portable architecture angle, and agree.  I'm looking more closely at the currency converter (PureMVC Multicore, Java) to wrap my head around what it's doing.  Maybe I'll have more thoughts about Intents at that point.

One intial problem to solve, one I ran into with the Flex hero SDK as well: when an Activity closes, its Mediator should be removed.  Same goes for starting an Activity.  This is a best practice anyway, but in the case of mobile development it's mandatory. 

I did this in a Command for the entire Flex application and it worked well, so I'm curious to see how it works in native Android.
11  PureMVC Manifold / Standard Version / Re: android on: March 28, 2011, 08:22:04
One thing I see in mobile, Android in particular, is poor separation of model from view.  People set data on the model from Activities, which contain GUI and kick off services and respond to user interactions in complex ways relative to the business logic.  They do too much, and know too much about each other, which imo is creating a lot of bad code as developers rush their apps to market in order to stay current.

I think a stripped-down port of puremvc would have a place, but I'm not sure Notifications would be necessary since the application already has Intents.  Perhaps Notification would extend Intent and be capable of transporting data?  Intent filters are declared in the manifest XML file, so Mediators seem unnecessary unless user interaction gets so complex in an Activity that it would benefit from mediation; but then it wouldn't be mediation, it most likely would be a view helper, accessed via composition.  Centralizing, decoupling or obfuscating the way Intents are sent would hide complexity, but introduce a learning curve to developers already struggling to learn the platform.

Commands would be useful to switch Activities, pass data to them, and persist application state.  Proxies that can also send Intents (Notifications) would be a good thing given how much more complex data manipulation in Android can become when you're dealing with cursors and native tables like raw contacts, not to mention SQLLite.

It's an interesting conversation. 

 
12  PureMVC Manifold / Standard Version / Re: android on: March 27, 2011, 06:59:26
Thanks for posting that.  I pursued for awhile, but put it on hold until I'd really mastered what I thought were widely understood best practices based on the SDK sample code and applications.

One thing I'm trying to decide is whether a native Android app needs a micro-architecture framework.  The scope is usually so limited relative to browser-based web applications that Activities' access to services (and a central application) seems adequate.

I may be wrong.  I guess only the future will tell.
13  PureMVC Manifold / Standard Version / Re: android on: February 10, 2011, 09:52:10
My Stack:

:
Thread [<1> main] (Suspended (exception RuntimeException))
ActivityThread.performLaunchActivity(ActivityThread$ActivityRecord, Intent) line: 2663
ActivityThread.handleLaunchActivity(ActivityThread$ActivityRecord, Intent) line: 2679
ActivityThread.access$2300(ActivityThread, ActivityThread$ActivityRecord, Intent) line: 125
ActivityThread$H.handleMessage(Message) line: 2033
ActivityThread$H(Handler).dispatchMessage(Message) line: 99
Looper.loop() line: 123
ActivityThread.main(String[]) line: 4627
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]
Method.invoke(Object, Object...) line: 521
ZygoteInit$MethodAndArgsCaller.run() line: 868
ZygoteInit.main(String[]) line: 626
NativeStart.main(String[]) line: not available [native method]

14  PureMVC Manifold / Standard Version / Re: android on: February 10, 2011, 09:46:50
I'm also trying to implement the standard version in Android, but running into problems.

My default Activity:

:
package com.britton.puremvcboilerplate;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;

public class HomeActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
   
    super.onCreate(savedInstanceState);
   
        setContentView(R.layout.main);
       
       ApplicationFacade facade = ApplicationFacade.getInstance();
       facade.startup(this);
       
    }
}

My ApplicationFacade:

:
package com.britton.puremvcboilerplate;

import org.puremvc.java.patterns.facade.Facade;

import android.app.Activity;

import com.britton.puremvcboilerplate.controller.SayHelloCommand;
import com.britton.puremvcboilerplate.controller.StartupCommand;

public class ApplicationFacade extends Facade {

/**
* Key of this facade.
*/
public static final String NAME = "ApplicationFacade";

/**
* Unique instance.
*/
private static ApplicationFacade instance = null;

public static final String STARTUP = "startup";
public static final String PREP_MODEL = "prep_model";
public static final String PREP_VIEW = "prep_view";
public static final String SAY_HELLO = "say_hello";
public static final String SAID_HELLO = "said_hello";

protected ApplicationFacade() {
super();
}

public static ApplicationFacade getInstance() {
if (instance == null) {
instance = new ApplicationFacade();
}
return instance;
}

public void startup(Activity app) {
sendNotification(STARTUP,app);
}

/* (non-Javadoc)
* @see org.puremvc.java.patterns.facade.Facade#initializeController()
*/
@Override
protected void initializeController() {

registerCommand(STARTUP, new StartupCommand());
registerCommand(SAY_HELLO, new SayHelloCommand());

super.initializeController();
}
}



Getting a null pointer exception (or something?) before I even call startup.  Should I be kicking everything off in an Activity, or somewhere else?  The Application?
15  PureMVC Manifold / Standard Version / Re: Flex Mobile ViewNavigator and PureMVC on: January 07, 2011, 07:57:26
My approach was to start the facade with my first view, then register the main mxml file's Mediator.  I have a Command for this with Notifications that start up each view's Mediator if it doesn't exist.

Now, however, I end up losing my Mediators unexpectedly.  Research continues...
Pages: [1] 2 3