Any memory efficient method to play frame animation on Android? - android

I have a requirement that asks for a looping of 100 images that are around 13kb each. At first I tried to use AnimationDrable and load them programatically like this:
public void animationPlay(){
frameAnimation = new AnimationDrawable();
String index = "00000";
for(int i = 1; i <= 100; i++)
{
if(i<10 ){
index = "0000" + i;
}else if(i< 100){
index = "000" + i;
}else if(i< 10000){
index = "00" + i;
}
String finalString = "acting_10_confetti" + index;
int frameIdentifier = getResources().getIdentifier(finalString, "drawable", getPackageName());
frameAnimation.addFrame(getResources().getDrawable(frameIdentifier), 70);
}
ImageView view = (ImageView) findViewById(R.id.imageView);
view.setBackground(frameAnimation);
frameAnimation.start();
}
The problem is as soon as I add the 10th frame, the app crashes with Out of Memory Error.
Has anyone came across this problem before?

Related

TfLite Image classification score is not consistent it keeps increasing for same image untill it reaches to some saturation(actual score)

With same instance of 'interpreter' score is getting increased for same image until it reaches at some saturation.
Interpreter tflite = new Interpreter(loadModelFile(context));
Create Instance for ImageClassifier and use the same instance to classify Frame and run inference for the same image.
ImageClassifier(Activity activity) throws IOException {
tflite = new Interpreter(loadModelFile(activity));
labelList = loadLabelList(activity);
imgData =
ByteBuffer.allocateDirect(
DIM_BATCH_SIZE
* getImageSizeX()
* getImageSizeY()
* DIM_PIXEL_SIZE
* getNumBytesPerChannel());
imgData.order(ByteOrder.nativeOrder());
filterLabelProbArray = new float[FILTER_STAGES][getNumLabels()];
Log.d(TAG, "Created a Tensorflow Lite Image Classifier.");
}
Classifies a frame for the same image. Same image can be picked up from the Sd card.
private void classifyImage() {
if (classifier == null || getActivity() == null || cameraDevice == null) {
showToast("Uninitialized Classifier or invalid context.");
return;
}
String imgPath = "/storage/emulated/0/DCIM/test.jpg";
Log.d("Image Path is %s", imgPath);
Bitmap bitmap = BitmapFactory.decodeFile(imgPath);
Bitmap newbitmap = Bitmap.createScaledBitmap(bitmap, 299, 299, false);
String textToShow = classifier.classifyFrame(newbitmap);
bitmap.recycle();
showToast(textToShow);
}
classifyFrame() Method of ImageClassifier.java
String classifyFrame(Bitmap bitmap) {
if (tflite == null) {
Log.e(TAG, "Image classifier has not been initialized; Skipped.");
return "Uninitialized Classifier.";
}
convertBitmapToByteBuffer(bitmap);
// Here's where the magic happens!!!
long startTime = SystemClock.uptimeMillis();
runInference();
long endTime = SystemClock.uptimeMillis();
Log.d(TAG, "Timecost to run model inference: " + Long.toString(endTime - startTime));
// Smooth the results across frames.
applyFilter();
// Print the results.
String textToShow = printTopKLabels();
textToShow = Long.toString(endTime - startTime) + "ms" + textToShow;
return textToShow;
}
applyFilter() method of ImageClassifier.java
void applyFilter() {
int numLabels = getNumLabels();
// Low pass filter `labelProbArray` into the first stage of the filter.
for (int j = 0; j < numLabels; ++j) {
filterLabelProbArray[0][j] +=
FILTER_FACTOR * (getProbability(j) - filterLabelProbArray[0][j]);
}
// Low pass filter each stage into the next.
for (int i = 1; i < FILTER_STAGES; ++i) {
for (int j = 0; j < numLabels; ++j) {
filterLabelProbArray[i][j] +=
FILTER_FACTOR * (filterLabelProbArray[i - 1][j] - filterLabelProbArray[i][j]);
}
}
// Copy the last stage filter output back to `labelProbArray`.
for (int j = 0; j < numLabels; ++j) {
setProbability(j, filterLabelProbArray[FILTER_STAGES - 1][j]);
}
}
Prints top-K labels, to be shown in UI as the results.
private String printTopKLabels() {
for (int i = 0; i < getNumLabels(); ++i) {
sortedLabels.add(
new AbstractMap.SimpleEntry<>(labelList.get(i), getNormalizedProbability(i)));
if (sortedLabels.size() > RESULTS_TO_SHOW) {
sortedLabels.poll();
}
}
String textToShow = "";
final int size = sortedLabels.size();
for (int i = 0; i < size; ++i) {
Map.Entry<String, Float> label = sortedLabels.poll();
textToShow = String.format("\n%s: %4.2f", label.getKey(), label.getValue()) + textToShow;
}
return textToShow;
}
At the first time when application gets launched score the image classification is 0.06 and then again if we called classifyImage() on some event click score gets increased to 0.13 and with same process it keeps increasing until it reached to 0.86(saturation).
I am not sure why its happening but it happened for both type of TfLite models inceptionV3 and MobileNet.
The results are filtered by the applyFilter method. It is a simple low pass filter, so the scores gradually arrive at their medium-term average. Comment out the call to applyFilter and it should respond instantly, but maybe too jittery for some applications.

two array dimensional ArrayIndexOutOfBoundException and NullPointerException

i wrote a code for calculating some weights. they are integer weights.
and i need to save them in every time the button is clicked.
please help me. i cant see why the compiler gives me an error when i try to push the button for the second time. here is my complete code:
public class TrainingActivity extends Activity {
private EditText etIn1, etIn2, etDesired;
private TextView prevInput;
int W[][] = new int[2][];
int X[][] = new int[30][];
int w0=0, w1=0, w2=0, p=1, sum=0, clicks=0;
private Button nxtData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.training_activity);
View backgroundImage = findViewById(R.id.background);
Drawable background = backgroundImage.getBackground();
background.setAlpha(40);
etIn1= (EditText) findViewById(R.id.etInput1);
etIn2 = (EditText) findViewById(R.id.etInput2);
etDesired = (EditText) findViewById(R.id.etDesired);
prevInput = (TextView) findViewById(R.id.prevInput);
nxtData = (Button) findViewById(R.id.nextData);
nxtData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
int sum = 0;
++clicks;
int intetIn1 = Integer.parseInt(etIn1.getText().toString());
int intetIn2 = Integer.parseInt(etIn2.getText().toString());
int intetDesired = Integer.parseInt(etDesired.getText().toString());
X[clicks-1] = new int[] {intetIn1, intetIn2, 1};
prevInput.setText("Last Inputs: (" + intetIn1 + ", " + intetIn2 +
", " + intetDesired + ")");
if(clicks == 1) {
if(intetDesired == 1) {
W[0] = new int[] {intetIn1, intetIn2, 1};
W[1] = W[0];
} else if(intetDesired == (-1)){
W[0] = new int[] {-intetIn1, -intetIn2, -1};
W[1] = W[0];
}
} else if(clicks > 1) {
for(int i=0; i<3; i++){
sum = sum + W[clicks-1][i] * X[clicks-1][i];
} if(sum>0 && intetDesired==1) {
W[clicks] = W[clicks-1];
} else if(sum<0 && intetDesired==(-1)) {
W[clicks] = W[clicks-1];
} else if(sum<=0 && intetDesired==1) {
for(int i=0; i<3; i++) {
W[clicks][i] = W[clicks-1][i] + X[clicks-1][i];
}
} else if(sum>=0 && intetDesired==(-1)) {
for(int i=0; i<3; i++) {
W[clicks][i] = W[clicks-1][i] - X[clicks-1][i];
}
}
}
etIn1.setText("");
etIn2.setText("");
etDesired.setText("");
}
});
}}
and here is the exception it throws:
java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
UPDATEEEEEEEE
i fixed the problem with arrayindexoutofboundexception by changing W[2][] to W[20][]. but in some clicks it gives me this error:
java.lang.NullPointerException
and it's not clear in which clicks. sometimes it's in the second click. or some times it's in fourth click. please help.
W[clicks] = W[clicks - 1];
in above line, you have get error because you have only define size of the array
int W[][] = new int[2][];
so it assigned W[0][] and W[1][] only
When click on second time variable clicks value is 2 then compiler gives ArrayIndexOutOfBoundException
EDITED.............................................................
you have got null value because of your bad logic and not proper way to build two dimensional array. Pls use debug tool to find the actual problem to implement logic and use two dimensional array like below example in java or android:
List<List<Integer>> triangle = new ArrayList<List<Integer>>();
List<Integer> row1 = new ArrayList<Integer>(1);
row1.add(2);
triangle.add(row1);
List<Integer> row2 = new ArrayList<Integer>(2);
row2.add(3);row2.add(4);
triangle.add(row2);
triangle.add(Arrays.asList(6,5,7));
triangle.add(Arrays.asList(4,1,8,3));
System.out.println("Size = "+ triangle.size());
for (int i=0; i<triangle.size();i++)
System.out.println(triangle.get(i));

Clicking One Button Effecting All

So, I have this android app that is supposibly a board game. It has multiple buttons on it, and when selected, I want the selected one to gain a boarder. But, for some reason, when pressing one, it selectes everything or just doesn't deselect. What am I forgetting to do or doing wrong? Because logically, it shouldn't change anything other than that tile. Their is no For loop with setImageBitmap!
onClickListener:
//set onCLickListener on each tile
public void setOnClickListenerOnTile(TileClass tileI){
ImageButton tile = (ImageButton) findViewById (tileI.getId());
tile.setOnClickListener(new OnClickListener (){
#Override
public void onClick (View V){
Log.i(TAG, "tileOnClick");
ImageButton tile = (ImageButton) findViewById (V.getId());
/*Following code checks if...
*1. if no tile is selected
*2. if the tile that is clicked is also the one that is selected
*3. if the tile selected is different than the one that is clicked*/
//if 1. happens, then add boarder
if (selectedTile == 0){
Log.i(TAG, "First Choice: 1");
//set tile with boarder
tile.setImageBitmap(modifyTile(1,color.blue, mapTile[findTileById(tile.getId(), mapTile)].tilePic));
//remember what tile is selected
selectedTile = V.getId();
}
//else if 2. happens, then remove boarder
else if (selectedTile == V.getId()){
Log.i(TAG, "First Choice: 2");
//set tile without boarder
tile.setImageBitmap(mapTile[findTileById(tile.getId(), mapTile)].tilePic);
tile.setImageBitmap(blankTileBitmap);
tile.refreshDrawableState();
//remember what tile is selected
selectedTile = 0;
}
//else if 3. happens, then remove the boarder on the selectedTile and add boarder on the clickedTile
else if (selectedTile != V.getId() && selectedTile != 0){
Log.i(TAG, "First Choice: 3");
//remove old boarder
ImageButton tempIB = (ImageButton) findViewById (selectedTile);
tempIB.setImageBitmap(mapTile[findTileById(selectedTile, mapTile)].tilePic);
//add new boarder
tile.setImageBitmap(modifyTile(1,color.blue, mapTile[findTileById(tile.getId(), mapTile)].tilePic));
//remember what tile is selected
selectedTile = V.getId();
}
}
});
}
modifyTile:
//Method function:
//to modify a tile
//modificationNum code:
//1: add boarders
//2: remove boarders
//Param: accepts the type of modifications as first parameter,
//color ID as listed in color resource (not Color),
//and a bitmap of the tile
//
public Bitmap modifyTile (int modificationNum, int color, Bitmap bitmap){
int count, count2;
Log.i(TAG, "modifyTile has been called!");
//first, find out which modification todo
//if modificationNum == 1, then it is to add a border
if (modificationNum == 1){
if (bitmap == null){
Log.i(TAG, "null error");
}
//set tile boarders on the top
for (count = 1; count < tileLength; count++){
bitmap.setPixel(count, 1, getResources().getColor(color));
}
//sides...
for (count = 1; count < (tileLength); count++){
bitmap.setPixel(1, count, getResources().getColor(color));
bitmap.setPixel((tileLength - 1), count, getResources().getColor(color));
}
//set tile boarders on the bottom
for (count = 1; count < tileLength; count++){
bitmap.setPixel(count-1, tileLength-1, getResources().getColor(color));
}
}
getAllTileId:
//get id of every tile (may take a long time) (not done)
public int[] getAllTileId (){
int count, count2;
Log.i(TAG, "getAllTileId has been called!");
//set up variables...
//have to set up a view for TableLayout so that I can find the tile's id using Tags (it has to be it's childs)
View v = (TableLayout) findViewById (R.id.mapTable);
ImageButton imageButton;
int temp, globalCount;
int results[] = new int[50];
for (count = 0, globalCount = 0; count < 9; count++ ){
if (count % 2 == 0){
temp = 6;
}
else{
temp = 5;
}
for (count2 = 0; count2 < temp; count2++, globalCount++){
imageButton = (ImageButton) v.findViewWithTag ("land" + (count + 1) + (count2 + 1));
results[globalCount] = imageButton.getId();
Log.i(TAG, "land #" + (count+1) + (count2+1) + "'s id = " + results[globalCount]);
}
}
Log.i(TAG, "getAllTileId length" + results.length);
return results;
}
findTileById:
//find a tile in an array using it's id
public int findTileById (int id, TileClass[] map){
Log.i(TAG, "findTileById has been called!");
int count=0;
for (count = 0; count < map.length && map[count].getId() != id; count++);
if (count >= map.length){
Log.i(TAG, "findTileById FAIL");
}
return count;
}
EDIT:
Here is onCreate:
//onCreate
#Override
public void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView (R.layout.activity_board);
//**TEST AREA, DELETE AFTER**
//**TEST AREA END**
//get the way to convert from dp to pixels and set up tileLength (in pixels)
metrics = getResources().getDisplayMetrics();
dpToPixels = metrics.density;
tileLength = (int) Math.ceil(44 * dpToPixels);
//set tilePic dimensions
tilePic = new int[tileLength * tileLength];
Log.i(TAG, "tileLength = " + tileLength + " and dpToPixels = " + dpToPixels);
//set up colors
blue = getResources().getColor(R.color.blue);
//set up blank selected tile bitmap
selectedTileBitmap = Bitmap.createBitmap(tileLength, tileLength, Bitmap.Config.ARGB_8888);
//set tile boarders
selectedTileBitmap = modifyTile (1, color.blue, selectedTileBitmap);
//set up blank tile bitmap
blankTileBitmap = Bitmap.createBitmap(tileLength, tileLength, Bitmap.Config.ARGB_8888);
for (count = 0; count < tileLength; count++){
for (count2 = 0; count2 < tileLength; count2++){
blankTileBitmap.setPixel(count, count2, getResources().getColor(color.white));
}
}
//first... get map tile ids...
mapTileId = new int [50];
mapTileId = getAllTileId ();
//set up mapTile
mapTile = new TileClass[50];
for (count = 0; count < 50; count++){
//first... get the tile (which is an ImageButton)
tempIB = (ImageButton) findViewById (mapTileId[count]);
//next step is to create a stringModifier to get the coordinates of the tile through it's tag
stringModifier = new StringBuilder (tempIB.getTag().toString());
//create the tile...
mapTile [count] = new TileClass (tempIB.getId(), Integer.parseInt(stringModifier.substring(4, 5)), Integer.parseInt(stringModifier.substring(5,6)), blankTileBitmap);
Log.i(TAG, "count = " + count);
Log.i(TAG, "test count" + mapTile[count].getId());
}
//set up all the bitmap of the tiles on screen
for (count = 0; count < 50; count++){
tempIB = (ImageButton) findViewById (mapTile [count].getId());
tempIB.setImageBitmap(mapTile[count].tilePic);
}
Log.i(TAG, "Finished setting up mapTile.");
//get id of every tile
//set up each tile with an onClick
for (count = 0; count < 50; count++){
setOnClickListenerOnTile(mapTile[count]);
}
}
Ok, I found my problem.
The user is able to click a button before onCreate is done, which is also before a lot of the arrays that are used to find / initialize other buttons are initialized. So, when the user clicks the button too fast, the array references to every button.

Programmatic ImageView android duplicate rows

So I have a function for an android app that is supposed to take any number of pictures and display them 5 pics for each row, for some reason when it goes to the second row, it just repeats the pics for the first row, for example if I have 7 pics numbered 1-7 they will display:
12345
12
here is my function, thanks for any advice.
public void generateImageView(int number, String path){
//ImageView[] imageViewArray = new ImageView[number];
int ROW_ITEMS = 5; // 5 images per row
RelativeLayout rl = (RelativeLayout) findViewById(R.id.RelativeLayout1);
int limit = number;//limits the number of created imageViews to number
int rows = limit / ROW_ITEMS;//number of rows
int leftOver = limit % ROW_ITEMS; //see if we have incomplete rows
if (leftOver != 0){
rows += 1;
}
int id = 1000;
int belowId = R.id.send;
while (rows > 0){
int realItemsPerRow = ROW_ITEMS;
if (leftOver != 0 & rows == 1){
realItemsPerRow = Math.min(ROW_ITEMS, leftOver);
}
for (int i = 0; i < realItemsPerRow; i++){
Bitmap myBitmap = BitmapFactory.decodeFile(path + i + ".png");
ImageView imageViewArray = new ImageView(MainActivity.this);
imageViewArray.setId(id);
imageViewArray.setImageBitmap(myBitmap);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
imageViewArray.setPadding(10,10,0,0);
imageViewArray.setAdjustViewBounds(true);
imageViewArray.setMaxHeight(80);
imageViewArray.setMaxWidth(80);
if (i==0) {
lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
} else {
lp.addRule(RelativeLayout.RIGHT_OF, imageViewArray.getId() -1);
}
lp.addRule(RelativeLayout.BELOW, belowId);
imageViewArray.setLayoutParams(lp);
rl.addView(imageViewArray);
id++;
}
belowId = id - 1;
rows--;
It's because you're just pulling the same images for each position in the row:
Bitmap myBitmap = BitmapFactory.decodeFile(path + i + ".png");
Before while( rows > 0 ) add:
int j = 0;
Then change the above to:
Bitmap myBitmap = BitmapFactory.decodeFile(path + ( j * ROW_ITEMS + i ) + ".png");
and under rows--; add:
j++;

Trying to set textview

Here is my class it goes in to infinite loop please check where I am going wrong ... I am trying to get id's of image view making it random and then trying to set text view with imageview's description
public class Object {
int ObectIds[];
LinearLayout HUDDisplay;
int HudDisplayText[] = {R.id.HUD_Text_Element1,
R.id.HUD_Text_Element2,
R.id.HUD_Text_Element3,
R.id.HUD_Text_Element4,
R.id.HUD_Text_Element5,
R.id.HUD_Text_Element6,
R.id.HUD_Text_Element7};
TextView[] text;
View v;
Object(Context context,View vs) {
super();
ObectIds = new int[8];
HUDDisplay=(LinearLayout)vs.findViewById(R.id.HUD_Display);
for (int i = 0; i < 8; i++) {
ObectIds[i] = (R.id.imageView1) + i;
Log.d("ImageView", "Image Id's " + ObectIds[i]);
}
randomize(vs);
setTextView();
}
public void setTextView()
{
for(int i=0;i<8;++i)
{
text[i] =(TextView) HUDDisplay.findViewById(HudDisplayText[i]);
text[i].setText(v.getContentDescription());
}
}
public void randomize(View vs) {
for (int i = 0; i < 8; i++) {
while (true) {
shuffleArray(ObectIds);
v = vs.findViewById(ObectIds[i]);
Log.d("Image", "Image Id's " + v.getId());
if (!v.isClickable()) {
v.setClickable(true);
break;
}
}
}
}
static void shuffleArray(int[] ar) {
Random rnd = new Random();
for (int i = ar.length - 1; i >= 0; i--) {
int index = rnd.nextInt(i + 1);
// Simple swap
int a = ar[index];
ar[index] = ar[i];
ar[i] = a;
}
}
}
Hey man I observed your code & found error in code :
Please compare following code with your code... Constructor
for (int i = 0; i < 8; i++) {
ObectIds[i] = **HudDisplayText[i]**;
Log.d("ImageView", "Image Id's " + ObectIds[i]);
}
You have a while(true) loop that you break from only if v is not clickable. What happens if v is clickable? Nothing in your code ever sets v to not clickable, and views by default are not clickable.
I notice you're using the Object class. Object is basically the root of which all classes extend. If you call super() in the constructor, it will call the super class constructor, which is Object as well... That might be the problem.
Try looking for tutorials on how to start with Java/Android, since you are also using variables names that are not recommended. E.g. in Java,:
- a Class starts with a Capital
- a variable, starts with lowercase
- a function starts with lowercase:
public class Captial
{
private int anIntegerStartsWithLowerCase;
private void functionsAreLowerCaseAsWell()
{
}
}
Also take a look at your loop... It looks like it is never ending

Categories

Resources