simplify intent dispatch

Too-clever double loop had an no-exit path. Now it's simpler: find a
fragment that can handle the intent, pop all fragments to its right
until it becomes top-most (there may be none), and then give it the
intent. Use of popBackStackImmediate() is required so old fragments are
gone before intent handling wants to create new ones.
This commit is contained in:
Eric House 2016-09-04 16:49:40 -07:00
parent c0eb827b77
commit 7358c1a185
4 changed files with 48 additions and 46 deletions

View file

@ -570,10 +570,11 @@ public class DelegateBase implements DlgClickNotify,
protected boolean isVisible() { return m_isVisible; } protected boolean isVisible() { return m_isVisible; }
protected boolean handleNewIntent( Intent intent ) { protected boolean canHandleNewIntent( Intent intent ) { return false; }
protected void handleNewIntent( Intent intent ) {
DbgUtils.logf( "%s.handleNewIntent(%s): not handling", DbgUtils.logf( "%s.handleNewIntent(%s): not handling",
getClass().getSimpleName(), intent.toString() ); getClass().getSimpleName(), intent.toString() );
return false; // not handled
} }
protected void runWhenActive( Runnable proc ) protected void runWhenActive( Runnable proc )

View file

@ -56,12 +56,11 @@ public class DualpaneDelegate extends DelegateBase {
} }
@Override @Override
protected boolean handleNewIntent( Intent intent ) protected void handleNewIntent( Intent intent )
{ {
MainActivity main = (MainActivity)m_activity; MainActivity main = (MainActivity)m_activity;
boolean handled = main.dispatchNewIntent( intent ); main.dispatchNewIntent( intent );
DbgUtils.logf( "DualpaneDelegate.handleNewIntent() => %b", handled ); DbgUtils.logf( "DualpaneDelegate.handleNewIntent()" );
return handled;
} }
@Override @Override

View file

@ -983,14 +983,19 @@ public class GamesListDelegate extends ListDelegateBase
} // init } // init
@Override @Override
protected boolean handleNewIntent( Intent intent ) protected boolean canHandleNewIntent( Intent intent )
{
return true;
}
@Override
protected void handleNewIntent( Intent intent )
{ {
m_launchedGames.clear(); m_launchedGames.clear();
Assert.assertNotNull( intent ); Assert.assertNotNull( intent );
invalRelayIDs( intent.getStringArrayExtra( RELAYIDS_EXTRA ) ); invalRelayIDs( intent.getStringArrayExtra( RELAYIDS_EXTRA ) );
reloadGame( intent.getLongExtra( ROWID_EXTRA, -1 ) ); reloadGame( intent.getLongExtra( ROWID_EXTRA, -1 ) );
tryStartsFromIntent( intent ); tryStartsFromIntent( intent );
return true; // handled it
} }
@Override @Override

View file

@ -169,56 +169,53 @@ public class MainActivity extends XWActivity
return handled; return handled;
} }
private void popIntoView( XWFragment newTopFrag )
{
FragmentManager fm = getSupportFragmentManager();
for ( ; ; ) {
int top = m_root.getChildCount() - 1;
if ( top < 0 ) {
break;
}
View child = m_root.getChildAt( top );
XWFragment frag = (XWFragment)fm.findFragmentById( child.getId() );
if ( frag == newTopFrag ) {
break;
}
String name = frag.getClass().getSimpleName();
DbgUtils.logdf( "MainActivity.popIntoView(): popping %d: %s", top, name );
fm.popBackStackImmediate();
DbgUtils.logdf( "MainActivity.popIntoView(): DONE popping %s",
name );
}
}
/** /**
* Run down the list of fragments until one handles the intent. If no * Run down the list of fragments until one can handle the intent. If
* visible one does, pop hidden ones into view until one of them * necessary, pop fragments above it until it comes into view. Then send
* does. Yes, this will take us back to GamesList being visible even if * it the event.
* nothing handles the intent, but at least now all are handled by
* GamesList anyway.
*/ */
private boolean dispatchNewIntentImpl( Intent intent ) private boolean dispatchNewIntentImpl( Intent intent )
{ {
boolean handled = false; boolean handled = false;
FragmentManager fm = getSupportFragmentManager(); FragmentManager fm = getSupportFragmentManager();
// First try non-left-most fragments, if any. Once we've eliminated for ( int ii = m_root.getChildCount() - 1; !handled && ii >= 0; --ii ) {
// them we can just iterate on the leftmost fragment. View child = m_root.getChildAt( ii );
int nNonLeft = m_maxPanes - 1; XWFragment frag = (XWFragment)fm.findFragmentById( child.getId() );
// include paged-to-left invisible views if ( null != frag ) {
int viewCount = m_root.getChildCount(); handled = frag.getDelegate().canHandleNewIntent( intent );
for ( int ii = nNonLeft; !handled && 0 < ii; --ii ) {
View child = m_root.getChildAt( viewCount - ii );
Fragment frag = fm.findFragmentById( child.getId() );
handled = ((XWFragment)frag).getDelegate().handleNewIntent( intent );
}
while ( !handled ) {
// Now iterate on the leftmost, popping if necessary to page new
// ones into place
int childCount = m_root.getChildCount();
int hiddenCount = Math.max( 0, childCount - m_maxPanes );
for ( int ii = hiddenCount; ii >= 0; --ii ) {
View child = m_root.getChildAt( ii );
if ( null == child ) {
DbgUtils.logf( "no child at index %d", ii );
continue;
}
Fragment frag = fm.findFragmentById( child.getId() );
// DbgUtils.logf( "left-most case (child %d): %s", hiddenCount,
// frag.getClass().getSimpleName() );
handled = ((XWFragment)frag).getDelegate()
.handleNewIntent( intent );
if ( handled ) { if ( handled ) {
break; popIntoView( frag );
} else if ( ii > 0 ) { frag.getDelegate().handleNewIntent( intent );
DbgUtils.logf( "popping %s",
frag.getClass().getSimpleName() );
fm.popBackStackImmediate(); // callback removes view
} }
} }
} }
if ( BuildConfig.DEBUG && !handled ) {
DbgUtils.showf( this, "dropping intent %s", intent.toString() );
DbgUtils.logdf( "dropping intent %s", intent.toString() );
}
return handled; return handled;
} }