howto calculate the memory usage of a android.graphics.Path - android

I am using an LRUCache to cache android.graphic.path objects. For that I need to know how many memory the pathes are using for overwriting the sizeOf() method of the LRUCache.
So my question is: How can I calculate the memory usage of a path ?
The difficulty what I already faced is:
The android.graphic.path is not serializable
path is probably stored as bitmap, what I read already ?
Primitivly measuring the memory usage as I did the following (Code) showed me confusing results. Example :
a path with 10'000 lines uses 312 bytes.
10 pathes with 10 lines each uses 992 bytes.
Any hints ?
ArrayList<Path> alPathes=new ArrayList<Path>();
long iAnzahlBigPathes=1;
long iAnzahlOperation4BigPath=20000;
System.gc();System.gc();System.gc();System.gc();System.gc();System.gc();System.gc();System.gc();
long lused1=getUsedMemory();
Log.v("Memory4operation","ltotal1 " + lused1);// getMemoryStatus
for(int o=0;o<iAnzahlBigPathes;o++){
Path path=getBigPath(iAnzahlOperation4BigPath);
int iSize=path.toString().length();
alPathes.add(path);
}
System.gc();System.gc();System.gc();System.gc();System.gc();System.gc();System.gc();System.gc();
long lused2=getUsedMemory();
Log.v("Memory4operation","ltotal2 " + lused2);// getMemoryStatus
long iDifferenz=lused2-lused1;
Log.v("Memory4operation", "Memory used for path " + iDifferenz + " in bytes");
//float fMemoryforoneline=(float)iDifferenz/(float)iAnzahlSquares;
float fMemoryforoneoperation=(float)iDifferenz/(float)iAnzahlOperation4BigPath/(float)iAnzahlBigPathes;
Log.v("Memory4operation", "" + fMemoryforoneoperation);
public long getUsedMemory(){
final int ltotal = (int) (Runtime.getRuntime().totalMemory());
final int lfree = (int) (Runtime.getRuntime().freeMemory());
return (ltotal - lfree);
}
public Path getBigPath(long iAnzahlOperation4BigPath){
int imin=10;
int imax=1000000;
Path path=new Path();
path.moveTo(randInt(imin,imax), randInt(imin,imax));
for(int i=0;i<iAnzahlOperation4BigPath;i++){
path.lineTo(randInt(imin,imax), randInt(imin,imax));
}
path.close();
return path;
}

Path will usually use hardware rendering when available. So internally it's not stored as a Bitmap but a set of "drawing instructions".
You'll have to look at Path's underlying native implementations (SkPath.cpp) to see how exactly a path is stored internally.
There doesn't seem to be an API available to get the size of the Path.
You're left with:
Look at the implementation and estimate it yourself. Remember that if you save the Path Object to the cache you're caching the instructions and not the rendered result.
Render your path to a bitmap before putting it into the LRUCache. This will save you rendering time. Especially if your paths are expensive to draw. That's most likely what you want anyway

Related

How to read kerning pairs table from TTF file in Android

I am currently drawing text on Canvas while using external (non-standard) font, loaded from TTF file. I want to enable kerning for the text I am displaying.
What I want to know is if there is a possibility to read kerning pairs from typeface using Android API.
What I want to know is if there is a possibility to read kerning pairs from typeface using Android API.
There is no public API to read kerning pairs from a TTF file. However, I pulled the relevant code from Apache FOP and you can read the kerning pairs using this library.
Example usage:
TTFFile file = TTFFile.open(getAssets().open("fonts/font.ttf"));
Map<Integer, Map<Integer, Integer>> kerning = file.getKerning();
You can also retrieve other metadata. Example:
TTFFile ttfFile = TTFFile.open(new File("/system/fonts/Roboto-Regular.ttf"));
String name = ttfFile.getFullName(); // "Roboto Regular"
String family = ttfFile.getSubFamilyName(); // "Regular"
int fontWeight = ttfFile.getWeightClass(); // 400
String copyright = ttfFile.getCopyrightNotice(); // "Font data copyright Google 2014"
I want to enable kerning for the text I am displaying.
See:
How to adjust text kerning in Android TextView?
setLetterSpacing(float)
I was willing to use the parser described above using standard Java on Windows. If anyone wants to do it, one needs to use Rectangle instead of Rect. This is just a minor conversion. I also eliminated the directory jaredrummler because it was a bit too long (I kept the copyright comments in the beginning of the files, though). But there are two TTFFile classes in this parser. This code:
TTFFile file;
File ttf = new File("C:\\Windows\\Fonts\\calibri.ttf" );
try { file = TTFFile.open(ttf); }
catch (IOException e) {e.printStackTrace(); }
Map<Integer, Map<Integer, Integer>> kerning = file.getKerning();
Only works if you import the correct class file:
import com.fontreader.truetype.TTFFile;
Finally, the code works but the kerning pairs returned don't work with the paths you convert using:
void vectorize(Path2D.Float path, String s) {
PathIterator pIter;
FontRenderContext frc = new FontRenderContext(null,true,true);
GlyphVector gv;
Shape glyph;
gv = font.createGlyphVector(frc, s);
glyph = gv.getGlyphOutline(0);
pIter = glyph.getPathIterator(null);
while (!pIter.isDone()) {
switch(pIter.currentSegment(points)) {
case PathIterator.SEG_MOVETO:
path.moveTo(points[0], points[1]);
break;
case PathIterator.SEG_LINETO :
path.lineTo(points[0], points[1]);
break;
case PathIterator.SEG_QUADTO :
path.quadTo(points[0], points[1], points[2], points[3]);
break;
case PathIterator.SEG_CUBICTO :
path.curveTo(points[0], points[1], points[2], points[3], points[4], points[5]);
break;
case PathIterator.SEG_CLOSE :
path.closePath();
}
pIter.next();
}
}
And lengths recovered by lens in the following code:
double interchar = fontsize * 0.075;
int size = '}' - ' ' + 1;
Path2D.Float[] glyphs = new Path2D.Float[size];
double[] lens = new double[size];
String chars[] = new String[size];
int i; char c;
char[] s = { '0' };
for (i = 0, c = ' '; c <= '}'; c++, i++) { s[0] = c; chars[i] = new String(s); }
for (i = 0; i < size; i++) {
vectorize(glyphs[i] = new Path2D.Float(), chars[i], tx[i], 0f);
lens[i] = glyphs[i].getBounds2D().getWidth() + interchar;
}
Just to be clear, I display the glyphs using fill in Graphics2D and I translate using the lengths above added to the kerning displacements returned by the library Apache FOP as suggested above, but the result is horrible. The fontsize is standard 1000 as suggested in this discussion and interchar results in 75, after multiplying by the font size. All this seems correct but my manual kerning pairs look far much better than using the kerning pairs from the ttf file.
Is there anyone trained with this library to be able to tell how we are supposed to use these kerning pairs?
Sorry for diverting slightly from the original question but this might complete the information since once one reads the kerning pairs how one uses them correctly on either Windows or Android?

How to make a random falling of bitmaps in Android?

I wanted to create something like jetboy asteroids that I found on android samples but i'ts too complicated to get the right code and to make it work properly.
I don't want on touch simply the asteroids should begin themselves.
Can someone link me some good stuff or give me some examples?
private void doAsteroidCreation() {
// Log.d(TAG, "asteroid created");
Asteroid _as = new Asteroid();
int drawIndex = mRandom.nextInt(4);
// TODO Remove hard coded value
_as.mDrawY = mAsteroidMinY + (drawIndex * 63);
_as.mDrawX = (mCanvasWidth - mAsteroids[0].getWidth());
_as.mStartTime = System.currentTimeMillis();
mDangerWillRobinson.add(_as);
}

Trying to only do math functions on edittexts users have entered information in on android

I have a 10-field average lap calculator. However, in testing, someone said they normally only run X laps in practice, vs. 10 (let's say 7).
I think I could use an if statement, but there'd be at least 10 of them and a bunch of clumsy code, and I'm not sure on arrays/switch statements exactly. I think all of those might be possible, but my low level of experience has yet to fully comprehend these useful tools.
CURRENT CODE:
double tenLapAvgVar = ((lap1Var + lap2Var + lap3Var + lap4Var + lap5Var + lap6Var + lap7Var + lap8Var + lap9Var + lap10Var) / 10);
So essentially, if someone leaves a field or fields blank, I want to calculate the average based on the populated fields, not 10 (if they leave 3 fields blank, calculate based on 7, for instance). Any help you guys could provide would be much appreciated, thanks!
You could have an ArrayList<EditText> object and a method which iterates over it and adds up the values. Something like:
public double getLapAverage()
{
int noOfCompletedLaps = 0;
double lapAve = 0;
double lapsTotal = 0;
for(EditText text : textBoxes)
{
if(text.getText().toString().length() > 0)
{
//psuedo code, and assuming text is numerical
lapsTotal += Double.parse(text.getText().toString());
noOfCompletedLaps++;
}
}
if( noOfCompletedLaps > 0)
{
lapAve = lapsTotal / noOfCompletedLaps;
}
return lapAve;
}
Maybe it would be better if you used an array instead of 10 different variables.
Then you can use a for statement and initialize them to 0, afterwords let the user fill the array and count how many are not zero.
Finally sum up all the array and divide by the count you previously calculated.

Large static float and double arrays causing App to slow down

This is more of a generic question which has to do with static variables and the process life cycle.
I have developed a heavy multi threaded signal processing Android app. It is targeted at API level 9 and above, and if I can it will restricted to only dual core devices. This is purely an academic App and not intended for the general user, and has been developed for teaching Digital Signal Processing. So for this reason I am calculating the DFT many times and so forth so there is quite a bit of computation and size allocation required.
I have declared a bunch of static float and double arrays which get used in static functions like in the example below. The complete code is is a bit to big to put here, so the example below just illustrates the idea.
public class SpecMod {
//Example of global static declarations
static double [][] spectrum = null;
static double [][] phaseMat = null;
static float [][] mframes = null;
static float [][] sframes = null;
static double [] mag = null;
static double [] Pxx = null;
static double [] GAMk = null;
static int nfft = 512;
static float nsegs = 560;
//Compute FFT data
public static void calcSpec(int fs, float [] buffer, float f, float g){
//Example of static array memory allocation
sframes = new float[nlen][(int) nsegs];
spectrum = new double[nfft][(int) nsegs];
phaseMat = new double[nfft][(int) nsegs];
mframes = new float[nlen][(int) nsegs];
mag = new double[nfft];
Pxx = new double[nfft];
GAMk = new double[nfft];
}
public static void fillArrays(){
//Example of array manipulation
for (int j = 0; j < nsegs; j++) {
for (int i = 0; i < nfft; i++) {
mag[i] = spectrum[i][j];
phase[i] = phaseMat[i][j];
Pxx[i] = Math.pow(Math.abs(mag[i]), 2);
GAMk[i] = (Pxx[i] / muPnn[i]);
}
}
}
}
The application is working great as it is. The problem lies in different execution times when say the function fillArrays() gets called. The first time the function is called it takes only 4 seconds to complete, however the second and each subsequent time it is run it takes closer to 30 seconds to complete. In log cat you can see that the heap size does increase drastically the second time, but every subsequent time it stays about the same. In MAT the two dimensional array 'spectrum' retains a large portion of heap. This is understandable as it would contain nfft*nsegs (512*560) sized data stored as doubles.
So I am not sure if the time taken is due to the Garbage collector or perhaps the interpreter going into each step of the for loops (strange tho if the first execution is still short). I thought maybe for all other arrays, setting them to non-static weakreferences so the garbage collector can clean them up, but it seems everything I try is to the same time effects.
So the question is, when using large array objects what is the most effective way to allocate space for them. At the moment they are static, but are not final as the size changes frequently due to user preference. Any help would be great thanks.
Note this is just example code, calcSpec() gets called each time the user changes parameters or a new audio file is loaded to compute frequency data 'spectrum', then only after calcSpec is called, the user can call fillArrays(). In terms of profiling, I have been using MemoryAnalyzer and allocation tracker. The odd thing here the time increase is only in fillArrays(). The first execution it take 4seconds, the second (without calling calcSpec() again, so the same spectrum data is used again) it takes 30 seconds. In both Mat and allocation tracker the Retained size and allocation size are the same for every execution.

Android: Set a random image using setImageResource

I need a help with setting a random image using setImageResource method.
In the drawable folder, I have a jpeg file named photo0.jpg, photo1.jpg...photo99.jpg.
And the following code works:
int p = R.drawable.photo1;
image.setImageResource(p);
The above will display photo1.jpg but I want to show a random image.
I tried the following but it doesn't work.
String a = "R.drawable.photo";
int n = (int) (Math.random()*100)
String b = Integer.toString(n);
String c = a+b;
int p = Integer.parseInt(c);//checkpoint
image.setImageResource(p);
It seems like the string "R.drawable.photoXX" isn't being changed to integer at the checkpoint.
Could someone please teach me a right code?
Thank you in advance.
Strings are pretty much evil when it comes to work like this due to the overhead costs. Since Android already provides you with integer id's I would recommend storing all of them to an int array and then using a random number for the index.
The code would look something like this:
int imageArr[] = new int[NUM_IMAGES];
imageArr[1] = R.drawable.photo;
//(load your array here with the resource ids)
int n = (int)Math.random()*NUM_IMAGES;
image.setImage(imageArr[n]);
Here we have a pretty straight forward implementation and bypass all the creation and destruction that occurs with the string concats.
maybe the error is here
int n = (int) (Math.random()*100)
put % not * Like this
int n = (int) (Math.random()%100)
to get all numbers under 100

Categories

Resources