mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-02 06:20:14 +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_pendingScore;
|
||||
private int m_dictPtr = 0;
|
||||
private String[] m_dictChars;
|
||||
protected String[] m_dictChars;
|
||||
private boolean m_hasSmallScreen;
|
||||
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 widthFor( int width ) { return (int)(width / m_widthProportion); }
|
||||
}
|
||||
private FontDims m_fontDims;
|
||||
protected FontDims m_fontDims;
|
||||
|
||||
public BoardCanvas( Activity activity, Bitmap bitmap, JNIThread jniThread,
|
||||
BoardDims dims )
|
||||
|
|
|
@ -135,7 +135,7 @@ public class DBUtils {
|
|||
DBHelper.DICTLANG, DBHelper.GAMEID,
|
||||
DBHelper.SCORES, DBHelper.HASMSGS,
|
||||
DBHelper.LASTPLAY_TIME, DBHelper.REMOTEDEVS,
|
||||
DBHelper.LASTMOVE, DBHelper.THUMBNAIL
|
||||
DBHelper.LASTMOVE
|
||||
};
|
||||
String selection = String.format( ROW_ID_FMT, lock.getRowid() );
|
||||
|
||||
|
@ -184,18 +184,6 @@ public class DBUtils {
|
|||
summary.lastMoveTime =
|
||||
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 =
|
||||
cursor.getString( cursor.getColumnIndex(DBHelper.SCORES));
|
||||
int[] scores = new int[summary.nPlayers];
|
||||
|
@ -322,8 +310,6 @@ public class DBUtils {
|
|||
}
|
||||
|
||||
values.put( DBHelper.SERVERROLE, summary.serverRole.ordinal() );
|
||||
|
||||
addThumb( summary.getThumbnail(), values );
|
||||
}
|
||||
|
||||
initDB( context );
|
||||
|
@ -447,7 +433,15 @@ public class DBUtils {
|
|||
long rowid = lock.getRowid();
|
||||
String selection = String.format( ROW_ID_FMT, rowid );
|
||||
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 );
|
||||
synchronized( s_dbHelper ) {
|
||||
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
|
||||
|
@ -957,15 +951,32 @@ public class DBUtils {
|
|||
s_groupsCache = null;
|
||||
}
|
||||
|
||||
private static void addThumb( Bitmap thumb, ContentValues values )
|
||||
public static Bitmap getThumb( Context context, long rowid )
|
||||
{
|
||||
if ( null == thumb ) {
|
||||
values.putNull( DBHelper.THUMBNAIL );
|
||||
} else {
|
||||
ByteArrayOutputStream bas = new ByteArrayOutputStream();
|
||||
thumb.compress( CompressFormat.PNG, 0, bas );
|
||||
values.put( DBHelper.THUMBNAIL, bas.toByteArray() );
|
||||
Bitmap thumb = null;
|
||||
if ( BuildConstants.THUMBNAIL_SUPPORTED ) {
|
||||
byte[] data = null;
|
||||
String[] columns = { DBHelper.THUMBNAIL };
|
||||
String selection = String.format( ROW_ID_FMT, rowid );
|
||||
|
||||
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
|
||||
|
|
|
@ -30,6 +30,7 @@ import android.os.AsyncTask;
|
|||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
@ -310,7 +311,6 @@ public class GameListItem extends LinearLayout
|
|||
|
||||
if ( BuildConstants.THUMBNAIL_SUPPORTED ) {
|
||||
m_thumb = (ImageView)findViewById( R.id.thumbnail );
|
||||
m_thumb.setImageBitmap( summary.getThumbnail() );
|
||||
}
|
||||
|
||||
tview = (TextView)findViewById( R.id.role );
|
||||
|
@ -340,11 +340,9 @@ public class GameListItem extends LinearLayout
|
|||
|
||||
private void makeThumbnailIf( boolean expanded )
|
||||
{
|
||||
if ( expanded && null != m_activity && null != m_summary
|
||||
&& null == m_summary.getThumbnail()
|
||||
if ( expanded && null != m_activity
|
||||
&& XWPrefs.getThumbEnabled( m_context ) ) {
|
||||
m_summary.setThumbnail( GameUtils.loadMakeBitmap( m_activity,
|
||||
m_rowid ) );
|
||||
enqueueGetThumbnail( this, m_rowid );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,4 +410,67 @@ public class GameListItem extends LinearLayout
|
|||
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.Rect;
|
||||
|
||||
import org.eehouse.android.xw4.jni.XwJNI;
|
||||
|
||||
public class ThumbCanvas extends BoardCanvas {
|
||||
|
||||
public ThumbCanvas( Activity activity, Bitmap bitmap )
|
||||
|
@ -47,4 +49,17 @@ public class ThumbCanvas extends BoardCanvas {
|
|||
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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
@ -69,7 +68,6 @@ public class GameSummary {
|
|||
private CurGameInfo m_gi;
|
||||
private Context m_context;
|
||||
private String[] m_remotePhones;
|
||||
private Bitmap m_thumb;
|
||||
|
||||
private GameSummary() {}
|
||||
|
||||
|
@ -89,16 +87,6 @@ public class GameSummary {
|
|||
m_gi = gi;
|
||||
}
|
||||
|
||||
public void setThumbnail( Bitmap thumb )
|
||||
{
|
||||
m_thumb = thumb;
|
||||
}
|
||||
|
||||
public Bitmap getThumbnail()
|
||||
{
|
||||
return m_thumb;
|
||||
}
|
||||
|
||||
public boolean inNetworkGame()
|
||||
{
|
||||
return null != relayID;
|
||||
|
|
Loading…
Reference in a new issue