diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java index cdab86ffa..1cf5e86c6 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java @@ -21,13 +21,14 @@ package org.eehouse.android.xw4; import android.widget.ListAdapter; import android.content.Context; +import android.os.AsyncTask; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.database.DataSetObserver; import java.io.FileInputStream; import java.util.Date; -import java.util.HashMap; +import java.util.HashMap; // class is not synchronized import java.text.DateFormat; import android.view.LayoutInflater; import android.widget.LinearLayout; @@ -43,10 +44,90 @@ public class GameListAdapter extends XWListAdapter { private LayoutInflater m_factory; private HashMap m_viewsCache; private DateFormat m_df; + private LoadItemCB m_cb; - public GameListAdapter( Context context ) { + public interface LoadItemCB { + public void itemLoaded( String path ); + } + + private class LoadItemTask extends AsyncTask { + private String m_path; + private Context m_context; + public LoadItemTask( Context context, String path ) + { + m_context = context; + m_path = path; + } + + @Override + protected Void doInBackground( Void... unused ) + { + View layout = m_factory.inflate( R.layout.game_list_item, null ); + boolean hideTitle = false;//CommonPrefs.getHideTitleBar(m_context); + GameSummary summary = DBUtils.getSummary( m_context, m_path, true ); + Assert.assertNotNull( summary ); + + TextView view = (TextView)layout.findViewById( R.id.game_name ); + if ( hideTitle ) { + view.setVisibility( View.GONE ); + } else { + String name = GameUtils.gameName( m_context, m_path ); + String format = + m_context.getString( R.string.str_game_namef ); + String lang = + DictLangCache.getLangName( m_context, + summary.dictLang ); + view.setText( String.format( format, name, lang ) ); + } + + LinearLayout list = + (LinearLayout)layout.findViewById( R.id.player_list ); + for ( int ii = 0; ii < summary.nPlayers; ++ii ) { + View tmp = m_factory.inflate( R.layout.player_list_elem, null ); + view = (TextView)tmp.findViewById( R.id.item_name ); + view.setText( summary.summarizePlayer( m_context, ii ) ); + view = (TextView)tmp.findViewById( R.id.item_score ); + view.setText( String.format( " %d", summary.scores[ii] ) ); + if ( summary.isNextToPlay( ii ) ) { + tmp.setBackgroundColor( 0x7F00FF00 ); + } + list.addView( tmp, ii ); + } + + view = (TextView)layout.findViewById( R.id.state ); + view.setText( summary.summarizeState( m_context ) ); + view = (TextView)layout.findViewById( R.id.modtime ); + view.setText( m_df.format( new Date( summary.modtime ) ) ); + + view = (TextView)layout.findViewById( R.id.role ); + String roleSummary = summary.summarizeRole( m_context ); + if ( null != roleSummary ) { + view.setText( roleSummary ); + } else { + view.setVisibility( View.GONE ); + } + + if ( summary.pendingMsgLevel != GameSummary.MSG_FLAGS_NONE ) { + View marker = layout.findViewById( R.id.msg_marker ); + marker.setVisibility( View.VISIBLE ); + } + synchronized( m_viewsCache ) { + m_viewsCache.put( m_path, layout ); + } + return null; + } // doInBackground + + @Override + protected void onPostExecute( Void unused ) + { + m_cb.itemLoaded( m_path ); + } + } // class LoadItemTask + + public GameListAdapter( Context context, LoadItemCB cb ) { super( context, DBUtils.gamesList(context).length ); m_context = context; + m_cb = cb; m_factory = LayoutInflater.from( context ); m_df = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT ); @@ -66,66 +147,25 @@ public class GameListAdapter extends XWListAdapter { public Object getItem( int position ) { final String path = DBUtils.gamesList(m_context)[position]; - View layout = m_viewsCache.get( path ); + View layout; + synchronized( m_viewsCache ) { + layout = m_viewsCache.get( path ); + } if ( null == layout ) { layout = m_factory.inflate( R.layout.game_list_item, null ); final boolean hideTitle = false;//CommonPrefs.getHideTitleBar( m_context ); - GameSummary summary = DBUtils.getSummary( m_context, path, false ); TextView view = (TextView)layout.findViewById( R.id.game_name ); if ( hideTitle ) { view.setVisibility( View.GONE ); } else { String text = GameUtils.gameName( m_context, path ); - if ( null != summary ) { - String format = - m_context.getString( R.string.str_game_namef ); - String lang = - DictLangCache.getLangName( m_context, - summary.dictLang ); - text = String.format( format, text, lang ); - } view.setText( text ); } - // If we can't read the summary right now we still need to - // return a view but shouldn't cache it - if ( null != summary ) { - LinearLayout list = - (LinearLayout)layout.findViewById( R.id.player_list ); - for ( int ii = 0; ii < summary.nPlayers; ++ii ) { - View tmp = m_factory.inflate( R.layout.player_list_elem, null ); - view = (TextView)tmp.findViewById( R.id.item_name ); - view.setText( summary.summarizePlayer( m_context, ii ) ); - view = (TextView)tmp.findViewById( R.id.item_score ); - view.setText( String.format( " %d", summary.scores[ii] ) ); - if ( summary.isNextToPlay( ii ) ) { - tmp.setBackgroundColor( 0x7F00FF00 ); - } - list.addView( tmp, ii ); - } - - view = (TextView)layout.findViewById( R.id.state ); - view.setText( summary.summarizeState( m_context ) ); - view = (TextView)layout.findViewById( R.id.modtime ); - view.setText( m_df.format( new Date( summary.modtime ) ) ); - - view = (TextView)layout.findViewById( R.id.role ); - String roleSummary = summary.summarizeRole( m_context ); - if ( null != roleSummary ) { - view.setText( roleSummary ); - } else { - view.setVisibility( View.GONE ); - } - - if ( summary.pendingMsgLevel != GameSummary.MSG_FLAGS_NONE ) { - View marker = layout.findViewById( R.id.msg_marker ); - marker.setVisibility( View.VISIBLE ); - } - m_viewsCache.put( path, layout ); - } + new LoadItemTask( m_context, path ).execute(); } // this doesn't work. Rather, it breaks highlighting because @@ -148,6 +188,8 @@ public class GameListAdapter extends XWListAdapter { public void inval( String key ) { - m_viewsCache.remove( key ); + synchronized( m_viewsCache ) { + m_viewsCache.remove( key ); + } } } \ No newline at end of file diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java index 22c723b0b..7980eed04 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java @@ -50,7 +50,8 @@ import org.eehouse.android.xw4.jni.*; public class GamesList extends XWListActivity implements DispatchNotify.HandleRelaysIface, - DBUtils.DBChangeListener { + DBUtils.DBChangeListener, + GameListAdapter.LoadItemCB { private static final int WARN_NODICT = DlgDelegate.DIALOG_LAST + 1; private static final int WARN_NODICT_SUBST = WARN_NODICT + 1; @@ -201,7 +202,7 @@ public class GamesList extends XWListActivity GameConverter.convert( this ); - m_adapter = new GameListAdapter( this ); + m_adapter = new GameListAdapter( this, this ); setListAdapter( m_adapter ); NetUtils.informOfDeaths( this ); @@ -281,6 +282,12 @@ public class GamesList extends XWListActivity } ); } + // GameListAdapter.LoadItemCB interface + public void itemLoaded( String path ) + { + onContentChanged(); + } + @Override public void onCreateContextMenu( ContextMenu menu, View view, ContextMenuInfo menuInfo )