Occasionally, the application I am building will run out of memory or receiving an error relating to bytes (Failed to allocate a 2320024 byte allocation with 125240 free bytes and 122KB until OOM, for example).
The app is very image heavy and relies on converting byte[] to bitmap (not generally recommended I know - but a necessary evil for this particular project). I keep receiving constant messages about "doing too much on the main thread." When it crashes, the source can be traced to my gridAdapter class, and sometimes my buildImage class (which uses gridAdapter)
I realize the proper approach would be to run the processes on another thread, but I keep running into difficulties. When I tried to run the "fillGrid()" and "fillPartialGrid()" methods on another thread - nothing appears when I run the application. When I try to use a new thread within the getView method of gridAdapter, I only end up with half an image. Furthermore, I have even managed to receive an error with it pointing to a location where I am using a separate thread (in buildImage).
If anyone could offer some advice on how to improve performance, I would be very grateful.
buildImage
public class buildImage extends AppCompatActivity {
private SimpleCursorAdapter adapter;
private ImageButton back;
ImageView buildContainer;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_build_image);
super.onCreate(savedInstanceState);
buildContainer = (ImageView) findViewById(R.id.fullSizeImage);
back = (ImageButton) findViewById(R.id.backButton);
back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, 60 * 2* 1000L);
}
protected void onStart() {
super.onStart();
Intent i = getIntent();
if (i.hasExtra("position"))
{
final int position = i.getExtras().getInt("position");
int lto = i.getExtras().getInt("lto");
int location = i.getExtras().getInt("location");
final gridAdapter adapter = new gridAdapter(this, lto, location);
new Thread(new Runnable() {
@Override
public void run() {
final Bitmap buildImage = BitmapFactory.decodeByteArray(adapter.buildImages.get(position), 0, adapter.buildImages.get(position).length);
buildContainer.post(new Runnable() {
@Override
public void run() {
buildContainer.setImageBitmap(buildImage);
}
});
}
}).start();
} else
{
byte[] imageId = i.getByteArrayExtra("imageID");
Bitmap buildImage = BitmapFactory.decodeByteArray(imageId, 0, imageId.length);
buildContainer.setImageBitmap(buildImage);
}
}
}
gridAdapter
public class gridAdapter extends BaseAdapter {
private Context mContext;
private int isLto;
private int board;
public Cursor items;
public ArrayList<String> itemNames = new ArrayList<String>();
public ArrayList<byte[]> icons = new ArrayList<byte[]>();
public ArrayList<byte[]> buildImages = new ArrayList<byte[]>();
public gridAdapter(Context context, int lto, int location) {
mContext = context;
isLto = lto;
board = location;
fillGrid();
}
public gridAdapter(Context context, int location, boolean homePage) {
mContext = context;
isLto = 1;
board = location;
fillPartialGrid();
}
private void fillGrid() {
databaseHelper dbHelper = new databaseHelper(mContext);
SQLiteDatabase db = dbHelper.getReadableDatabase();
items = db.rawQuery("SELECT " + databaseHelper.ITEM_NAME + ", " + databaseHelper.ICON + ", " + databaseHelper.IMAGE + " FROM " + databaseHelper.TABLE_NAME + " where " + databaseHelper.LTO + " = " + isLto + " and " + databaseHelper.LOCATION + " = " + board + " ORDER BY " + databaseHelper.ITEM_NAME + " ASC", null);
items.moveToFirst();
int counter = 0;
while(!items.isAfterLast()) {
itemNames.add(items.getString(items.getColumnIndex(databaseHelper.ITEM_NAME)));
icons.add(items.getBlob(items.getColumnIndex(databaseHelper.ICON)));
buildImages.add(items.getBlob(items.getColumnIndex(databaseHelper.IMAGE)));
counter++;
items.moveToNext();
}
items.close();
db.close();
dbHelper.database.close();
}
private void fillPartialGrid() {
databaseHelper dbHelper = new databaseHelper(mContext);
SQLiteDatabase db = dbHelper.getReadableDatabase();
items = db.rawQuery("SELECT " + databaseHelper.ITEM_NAME + ", " + databaseHelper.ICON + ", " + databaseHelper.IMAGE + " FROM " + databaseHelper.TABLE_NAME + " where " + databaseHelper.LTO + " = " + isLto + " and " + databaseHelper.LOCATION + " = " + board + " ORDER BY " + databaseHelper.ITEM_NAME + " ASC LIMIT 3", null);
items.moveToFirst();
int counter = 0;
while(!items.isAfterLast()) { itemNames.add(items.getString(items.getColumnIndex(databaseHelper.ITEM_NAME)));
icons.add(items.getBlob(items.getColumnIndex(databaseHelper.ICON)));
buildImages.add(items.getBlob(items.getColumnIndex(databaseHelper.IMAGE)));
counter++;
items.moveToNext();
}
items.close();
db.close();
dbHelper.database.close();
}
@Override
public int getCount() {
return itemNames.size();
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public Object getItem(int position) {
return buildImages.get(position);
}
@Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater layout = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layout.inflate(R.layout.grid_item, parent, false);
TextView gridItemName = (TextView)view.findViewById(R.id.gridItemName);
ImageView iconContainer = (ImageView)view.findViewById(R.id.gridItemIcon);
gridItemName.setText(itemNames.get(position));
Bitmap iconBitmap = BitmapFactory.decodeByteArray(icons.get(position), 0, icons.get(position).length);
iconContainer.setImageBitmap(iconBitmap);
return view;
}
}
and an example of another activity that uses gridAdapter and leads to buildImage
public class lunchStandard extends AppCompatActivity {
private String release = Build.VERSION.RELEASE;
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.configure_icon:
Intent i = new Intent(this, preferences.class);
startActivity(i);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private int discriminator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lunch_standard);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setClipChildren(false);
toolbar.setNavigationIcon(R.drawable.back);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(lunchStandard.this, launch_activity.class);
startActivity(i);
}
});
GridView grid = (GridView) findViewById(R.id.lunchStandardGrid);
SharedPreferences preferences = getSharedPreferences("config", MODE_PRIVATE);
if(preferences.getInt("Location", 2) == 3) {
discriminator = 3;
} else if(preferences.getInt("Location", 2) == 2){
discriminator = 2;
}
if(discriminator == 2) {
setTitle("Main Boards Builds " + release);
} else if (discriminator == 3) {
setTitle("Speciality Builds " + release);
}
gridAdapter adapter = new gridAdapter(this, 0, discriminator);
grid.setAdapter(adapter);
grid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(lunchStandard.this, buildImage.class);
intent.putExtra("location", discriminator);
intent.putExtra("lto", 0);
intent.putExtra("position", position);
startActivity(intent);
}
});
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent i = new Intent(lunchStandard.this, midamcorp.com.burgerkingapp.preferences.class);
startActivity(i);
}
});
}
}