mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-04 23:02:02 +01:00
fix (I hope) OOM errors when there are a ton of games by doing
snapshot creation and loading sequentially on a single thread so that peak memory consumed by bitmap operations is lower. Remove snapshots from GameSummary: the db is the only source now.
This commit is contained in:
parent
d2c87647cd
commit
6f4cb4b0ca
5 changed files with 117 additions and 42 deletions
|
@ -82,7 +82,7 @@ public class BoardCanvas extends Canvas implements DrawCtx {
|
||||||
private int m_trayOwner = -1;
|
private int m_trayOwner = -1;
|
||||||
private int m_pendingScore;
|
private int m_pendingScore;
|
||||||
private int m_dictPtr = 0;
|
private int m_dictPtr = 0;
|
||||||
private String[] m_dictChars;
|
protected String[] m_dictChars;
|
||||||
private boolean m_hasSmallScreen;
|
private boolean m_hasSmallScreen;
|
||||||
private int m_backgroundUsed = 0x00000000;
|
private int m_backgroundUsed = 0x00000000;
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ public class BoardCanvas extends Canvas implements DrawCtx {
|
||||||
int descentFor( int ht ) { return (int)(ht * m_descentProportion); }
|
int descentFor( int ht ) { return (int)(ht * m_descentProportion); }
|
||||||
int widthFor( int width ) { return (int)(width / m_widthProportion); }
|
int widthFor( int width ) { return (int)(width / m_widthProportion); }
|
||||||
}
|
}
|
||||||
private FontDims m_fontDims;
|
protected FontDims m_fontDims;
|
||||||
|
|
||||||
public BoardCanvas( Activity activity, Bitmap bitmap, JNIThread jniThread,
|
public BoardCanvas( Activity activity, Bitmap bitmap, JNIThread jniThread,
|
||||||
BoardDims dims )
|
BoardDims dims )
|
||||||
|
|
|
@ -135,7 +135,7 @@ public class DBUtils {
|
||||||
DBHelper.DICTLANG, DBHelper.GAMEID,
|
DBHelper.DICTLANG, DBHelper.GAMEID,
|
||||||
DBHelper.SCORES, DBHelper.HASMSGS,
|
DBHelper.SCORES, DBHelper.HASMSGS,
|
||||||
DBHelper.LASTPLAY_TIME, DBHelper.REMOTEDEVS,
|
DBHelper.LASTPLAY_TIME, DBHelper.REMOTEDEVS,
|
||||||
DBHelper.LASTMOVE, DBHelper.THUMBNAIL
|
DBHelper.LASTMOVE
|
||||||
};
|
};
|
||||||
String selection = String.format( ROW_ID_FMT, lock.getRowid() );
|
String selection = String.format( ROW_ID_FMT, lock.getRowid() );
|
||||||
|
|
||||||
|
@ -184,18 +184,6 @@ public class DBUtils {
|
||||||
summary.lastMoveTime =
|
summary.lastMoveTime =
|
||||||
cursor.getInt(cursor.getColumnIndex(DBHelper.LASTMOVE));
|
cursor.getInt(cursor.getColumnIndex(DBHelper.LASTMOVE));
|
||||||
|
|
||||||
if ( BuildConstants.THUMBNAIL_SUPPORTED ) {
|
|
||||||
byte[] data =
|
|
||||||
cursor.getBlob( cursor.
|
|
||||||
getColumnIndex(DBHelper.THUMBNAIL));
|
|
||||||
if ( null != data ) {
|
|
||||||
Bitmap thumb =
|
|
||||||
BitmapFactory.decodeByteArray( data, 0,
|
|
||||||
data.length );
|
|
||||||
summary.setThumbnail( thumb );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String scoresStr =
|
String scoresStr =
|
||||||
cursor.getString( cursor.getColumnIndex(DBHelper.SCORES));
|
cursor.getString( cursor.getColumnIndex(DBHelper.SCORES));
|
||||||
int[] scores = new int[summary.nPlayers];
|
int[] scores = new int[summary.nPlayers];
|
||||||
|
@ -322,8 +310,6 @@ public class DBUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
values.put( DBHelper.SERVERROLE, summary.serverRole.ordinal() );
|
values.put( DBHelper.SERVERROLE, summary.serverRole.ordinal() );
|
||||||
|
|
||||||
addThumb( summary.getThumbnail(), values );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initDB( context );
|
initDB( context );
|
||||||
|
@ -447,7 +433,15 @@ public class DBUtils {
|
||||||
long rowid = lock.getRowid();
|
long rowid = lock.getRowid();
|
||||||
String selection = String.format( ROW_ID_FMT, rowid );
|
String selection = String.format( ROW_ID_FMT, rowid );
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
addThumb( thumb, values );
|
|
||||||
|
if ( null == thumb ) {
|
||||||
|
values.putNull( DBHelper.THUMBNAIL );
|
||||||
|
} else {
|
||||||
|
ByteArrayOutputStream bas = new ByteArrayOutputStream();
|
||||||
|
thumb.compress( CompressFormat.PNG, 0, bas );
|
||||||
|
values.put( DBHelper.THUMBNAIL, bas.toByteArray() );
|
||||||
|
}
|
||||||
|
|
||||||
initDB( context );
|
initDB( context );
|
||||||
synchronized( s_dbHelper ) {
|
synchronized( s_dbHelper ) {
|
||||||
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
||||||
|
@ -957,15 +951,32 @@ public class DBUtils {
|
||||||
s_groupsCache = null;
|
s_groupsCache = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addThumb( Bitmap thumb, ContentValues values )
|
public static Bitmap getThumb( Context context, long rowid )
|
||||||
{
|
{
|
||||||
if ( null == thumb ) {
|
Bitmap thumb = null;
|
||||||
values.putNull( DBHelper.THUMBNAIL );
|
if ( BuildConstants.THUMBNAIL_SUPPORTED ) {
|
||||||
} else {
|
byte[] data = null;
|
||||||
ByteArrayOutputStream bas = new ByteArrayOutputStream();
|
String[] columns = { DBHelper.THUMBNAIL };
|
||||||
thumb.compress( CompressFormat.PNG, 0, bas );
|
String selection = String.format( ROW_ID_FMT, rowid );
|
||||||
values.put( DBHelper.THUMBNAIL, bas.toByteArray() );
|
|
||||||
|
initDB( context );
|
||||||
|
synchronized( s_dbHelper ) {
|
||||||
|
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
|
||||||
|
Cursor cursor = db.query( DBHelper.TABLE_NAME_SUM, columns,
|
||||||
|
selection, null, null, null, null );
|
||||||
|
if ( 1 == cursor.getCount() && cursor.moveToFirst() ) {
|
||||||
|
data = cursor.getBlob( cursor.
|
||||||
|
getColumnIndex(DBHelper.THUMBNAIL));
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null != data ) {
|
||||||
|
thumb = BitmapFactory.decodeByteArray( data, 0, data.length );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return thumb;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return map of string (group name) to info about all games in
|
// Return map of string (group name) to info about all games in
|
||||||
|
|
|
@ -30,6 +30,7 @@ import android.os.AsyncTask;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
@ -310,7 +311,6 @@ public class GameListItem extends LinearLayout
|
||||||
|
|
||||||
if ( BuildConstants.THUMBNAIL_SUPPORTED ) {
|
if ( BuildConstants.THUMBNAIL_SUPPORTED ) {
|
||||||
m_thumb = (ImageView)findViewById( R.id.thumbnail );
|
m_thumb = (ImageView)findViewById( R.id.thumbnail );
|
||||||
m_thumb.setImageBitmap( summary.getThumbnail() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tview = (TextView)findViewById( R.id.role );
|
tview = (TextView)findViewById( R.id.role );
|
||||||
|
@ -340,11 +340,9 @@ public class GameListItem extends LinearLayout
|
||||||
|
|
||||||
private void makeThumbnailIf( boolean expanded )
|
private void makeThumbnailIf( boolean expanded )
|
||||||
{
|
{
|
||||||
if ( expanded && null != m_activity && null != m_summary
|
if ( expanded && null != m_activity
|
||||||
&& null == m_summary.getThumbnail()
|
|
||||||
&& XWPrefs.getThumbEnabled( m_context ) ) {
|
&& XWPrefs.getThumbEnabled( m_context ) ) {
|
||||||
m_summary.setThumbnail( GameUtils.loadMakeBitmap( m_activity,
|
enqueueGetThumbnail( this, m_rowid );
|
||||||
m_rowid ) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,4 +410,67 @@ public class GameListItem extends LinearLayout
|
||||||
toggleSelected();
|
toggleSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class ThumbQueueElem {
|
||||||
|
public ThumbQueueElem( GameListItem item, long rowid ) {
|
||||||
|
m_item = item;
|
||||||
|
m_rowid = rowid;
|
||||||
|
}
|
||||||
|
long m_rowid;
|
||||||
|
GameListItem m_item;
|
||||||
|
}
|
||||||
|
private static LinkedBlockingQueue<ThumbQueueElem> s_queue
|
||||||
|
= new LinkedBlockingQueue<ThumbQueueElem>();
|
||||||
|
private static Thread s_thumbThread;
|
||||||
|
|
||||||
|
private static void enqueueGetThumbnail( GameListItem item, long rowid )
|
||||||
|
{
|
||||||
|
if ( BuildConstants.THUMBNAIL_SUPPORTED ) {
|
||||||
|
s_queue.add( new ThumbQueueElem( item, rowid ) );
|
||||||
|
|
||||||
|
synchronized( GameListItem.class ) {
|
||||||
|
if ( null == s_thumbThread ) {
|
||||||
|
s_thumbThread = makeThumbThread();
|
||||||
|
s_thumbThread.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Thread makeThumbThread()
|
||||||
|
{
|
||||||
|
return new Thread( new Runnable() {
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
for ( ; ; ) {
|
||||||
|
ThumbQueueElem elem;
|
||||||
|
try {
|
||||||
|
elem = s_queue.take();
|
||||||
|
} catch ( InterruptedException ie ) {
|
||||||
|
DbgUtils.logf( "interrupted; killing "
|
||||||
|
+ "s_thumbThread" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Activity activity = elem.m_item.m_activity;
|
||||||
|
long rowid = elem.m_rowid;
|
||||||
|
Bitmap thumb = DBUtils.getThumb( activity, rowid );
|
||||||
|
if ( null == thumb ) {
|
||||||
|
// loadMakeBitmap puts in DB
|
||||||
|
thumb = GameUtils.loadMakeBitmap( activity, rowid );
|
||||||
|
}
|
||||||
|
|
||||||
|
final GameListItem item = elem.m_item;
|
||||||
|
final Bitmap ft = thumb;
|
||||||
|
activity.runOnUiThread( new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
ImageView iview = item.m_thumb;
|
||||||
|
if ( null != iview ) {
|
||||||
|
iview.setImageBitmap( ft );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ import android.app.Activity;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
import org.eehouse.android.xw4.jni.XwJNI;
|
||||||
|
|
||||||
public class ThumbCanvas extends BoardCanvas {
|
public class ThumbCanvas extends BoardCanvas {
|
||||||
|
|
||||||
public ThumbCanvas( Activity activity, Bitmap bitmap )
|
public ThumbCanvas( Activity activity, Bitmap bitmap )
|
||||||
|
@ -47,4 +49,17 @@ public class ThumbCanvas extends BoardCanvas {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unlike superclass, where the game was loaded on the main thread
|
||||||
|
// but dictChanged() is called on the JNI thread, this instance
|
||||||
|
// will have been created on the same background thread that's
|
||||||
|
// calling us. So don't switch threads for the dict_getChars()
|
||||||
|
// call
|
||||||
|
@Override
|
||||||
|
public void dictChanged( final int dictPtr )
|
||||||
|
{
|
||||||
|
if ( 0 != dictPtr ) {
|
||||||
|
m_fontDims = null;
|
||||||
|
m_dictChars = XwJNI.dict_getChars( dictPtr );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
package org.eehouse.android.xw4.jni;
|
package org.eehouse.android.xw4.jni;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
@ -69,7 +68,6 @@ public class GameSummary {
|
||||||
private CurGameInfo m_gi;
|
private CurGameInfo m_gi;
|
||||||
private Context m_context;
|
private Context m_context;
|
||||||
private String[] m_remotePhones;
|
private String[] m_remotePhones;
|
||||||
private Bitmap m_thumb;
|
|
||||||
|
|
||||||
private GameSummary() {}
|
private GameSummary() {}
|
||||||
|
|
||||||
|
@ -89,16 +87,6 @@ public class GameSummary {
|
||||||
m_gi = gi;
|
m_gi = gi;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setThumbnail( Bitmap thumb )
|
|
||||||
{
|
|
||||||
m_thumb = thumb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bitmap getThumbnail()
|
|
||||||
{
|
|
||||||
return m_thumb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean inNetworkGame()
|
public boolean inNetworkGame()
|
||||||
{
|
{
|
||||||
return null != relayID;
|
return null != relayID;
|
||||||
|
|
Loading…
Reference in a new issue