Android How to run an AsyncTask every second? - android

I'm new in Android and not really knowing how to deal this problem: I have an AsyncTask which reads a position (X,Y,Z) from a XML file. As this position changes every second, I want, after I push a button (called with "StartListener") to read and draw every new position CONTINUOUSLY and stop reading it when I press the button again...
Somebody can help me? - Here is a part of my MainActivity
(For the moment my app reads and draws a position only when I press the button...)
private OnClickListener StartListener = new OnClickListener() {
#Override
public void onClick(View v) {
TextView ButText = (TextView)findViewById(R.id.buttonStart);
String value=ButText.getText().toString();
if(value.equals("Start positioning")){
ButText.setText("Stop positioning");
new PositionAsync().execute(); //read data from XML file
}
else if(value.equals("Stop positioning")){
ButText.setText("Start positioning");
//new PositionAsync().cancel(true);
}
}
}; // END LISTENER START BUTTON
// READ XML FILE
class PositionAsync extends AsyncTask<Void, Void, Void> {
XMLHelper helper;
#Override
protected Void doInBackground(Void... arg0) {
helper = new XMLHelper();
helper.get();
return null;
}
#Override
protected void onPostExecute(Void result) {
Paint paintBlack = new Paint(); paintBlack.setAntiAlias(true); paintBlack.setColor(Color.BLACK);
BitmapFactory.Options myOptions = new BitmapFactory.Options();
myOptions.inDither = true;
myOptions.inScaled = false;
myOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;// important
myOptions.inPurgeable = true;
File ImageSource = new File("/sdcard/app_background3.jpg");
Bitmap bitmap2 = BitmapFactory.decodeFile(ImageSource.getAbsolutePath(),myOptions);
Bitmap workingBitmap = Bitmap.createBitmap(bitmap2);
Bitmap mutableBitmap2 = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas2 = new Canvas(mutableBitmap2);
float RoomWidthPx = canvas2.getWidth();
float RoomHeightPx = canvas2.getHeight();
float RoomXmeter = (float) 9.3;
float RoomZmeter = (float) 14.7;
for (PositionValue position : helper.positions) {
String PosX = position.getPositionX(); String PosY = position.getPositionY(); String PosZ = position.getPositionZ();
float x = Float.valueOf(PosX); float y = Float.valueOf(PosY); float z = Float.valueOf(PosZ);
float xm = x*RoomWidthPx/RoomXmeter;
float zm = z*RoomHeightPx/RoomZmeter;
canvas2.drawCircle(xm, zm, 25, paintBlack);
ImageView imageView = (ImageView)findViewById(R.id.imageView1);
imageView.setAdjustViewBounds(true);
imageView.setImageBitmap(mutableBitmap2);
// SAVE DRAWINGS INTO FILE
FileOutputStream fos = null;
try {
fos = new FileOutputStream ("/sdcard/app_background3.jpg");
mutableBitmap2.compress (Bitmap.CompressFormat.JPEG, 95, fos);
} catch (Throwable ex) {ex.printStackTrace (); }
};
}
} //END READ XML FILE

I think you are doing too many task in just one second. You could, instead, prepare all heavy staff in the onPreExecute() of the AsyncTask, read the XML and do the painting in the doInBackground(), resfresh the ImageView in the onProgressUpdate() and finally, when the task is done, save the image to the sdcard.
I've modified your Asynctask to accomplish the above scenario, I've not tested it but it gives you the idea.
In the onCreate() method of your activity you start the AsyncTask just once. It stays executing or sleeping until you set the Quit_Task variable to true. When the button is pressed you toggle the variable Do_Drawing: Do_Drawing=!Do_Drawing; and that's it.
private boolean Do_Drawing = false;
private boolean Quit_Task = false;
// READ XML FILE
class PositionAsync extends AsyncTask<Void, Void, Void>
{
Paint paintBlack;
BitmapFactory.Options myOptions;
Bitmap mutableBitmap2;
Canvas canvas2;
XMLHelper helper;
void Sleep(int ms)
{
try
{
Thread.sleep(ms);
}
catch (Exception e)
{
}
}
#Override
protected void onPreExecute()
{
// Prepare everything for doInBackground thread
paintBlack = new Paint();
paintBlack.setAntiAlias(true);
paintBlack.setColor(Color.BLACK);
myOptions = new BitmapFactory.Options();
myOptions.inDither = true;
myOptions.inScaled = false;
myOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;// important
myOptions.inPurgeable = true;
File ImageSource = new File("/sdcard/app_background3.jpg");
Bitmap bitmap2 = BitmapFactory.decodeFile(ImageSource.getAbsolutePath(), myOptions);
Bitmap workingBitmap = Bitmap.createBitmap(bitmap2);
mutableBitmap2 = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
canvas2 = new Canvas(mutableBitmap2);
helper = new XMLHelper();
}
#Override
protected Void doInBackground(Void... arg0)
{
while (!Quit_Task)
{
// Sleep until button is pressed or quit
while (!Do_Drawing)
{
Sleep(1000);
if (Quit_Task)
return null;
}
float RoomWidthPx = canvas2.getWidth();
float RoomHeightPx = canvas2.getHeight();
float RoomXmeter = (float) 9.3;
float RoomZmeter = (float) 14.7;
// keep drawing until button is pressed again or quit
while (Do_Drawing)
{
if (Quit_Task)
return null;
helper.get();
for (PositionValue position : helper.positions)
{
String PosX = position.getPositionX();
String PosY = position.getPositionY();
String PosZ = position.getPositionZ();
float x = Float.valueOf(PosX);
float y = Float.valueOf(PosY);
float z = Float.valueOf(PosZ);
float xm = x * RoomWidthPx / RoomXmeter;
float zm = z * RoomHeightPx / RoomZmeter;
canvas2.drawCircle(xm, zm, 25, paintBlack);
}
this.publishProgress((Void) null);
Sleep(1000);
}
}
return null;
}
#Override
protected void onProgressUpdate(Void... progress)
{
// once all points are read & drawn refresh the imageview
try
{
ImageView imageView = (ImageView) findViewById(R.id.imageView1);
imageView.setAdjustViewBounds(true);
imageView.setImageBitmap(mutableBitmap2);
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Override
protected void onPostExecute(Void result)
{
// SAVE DRAWINGS INTO FILE once the task is done.
FileOutputStream fos = null;
try
{
fos = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "app_background3.jpg");
mutableBitmap2.compress(Bitmap.CompressFormat.JPEG, 95, fos);
}
catch (Throwable ex)
{
ex.printStackTrace();
}
}
} // END READ XML FILE

you can use Handlers to deal with this:
private boolean isBusy = false;//this flag to indicate whether your async task completed or not
private boolean stop = false;//this flag to indicate whether your button stop clicked
private Handler handler = new Handler();
public void startHandler()
{
handler.postDelayed(new Runnable()
{
#Override
public void run()
{
if(!isBusy) callAysncTask();
if(!stop) startHandler();
}
}, 1000);
}
private void callAysncTask()
{
//TODO
new PositionAsync().execute();
}
set isBusy to true when the async task in doInBackground and set it back to false in the last line of onPostExecute.
when you click stop button set stop to true, when click start button set stop to false

Related

Android outofmemory bitmap

I have used the following animation class because i have multiple images to make an animation. After the 7th animation i get OutofMemoryError. androidgraphics.Bitmap.createBitmap
public class AnimationsContainer {
public int FPS = 30; // animation FPS
// single instance procedures
private static AnimationsContainer mInstance;
private AnimationsContainer() {
};
public static AnimationsContainer getInstance() {
if (mInstance == null)
mInstance = new AnimationsContainer();
return mInstance;
}
// animation progress dialog frames
private int[] mProgressAnimFrames = {};
// animation splash screen frames
/**
* #param imageView
* #return progress dialog animation
*/
public FramesSequenceAnimation createProgressDialogAnim(ImageView imageView) {
return new FramesSequenceAnimation(imageView, mProgressAnimFrames);
}
/**
* #param imageView
* #return splash screen animation
*/
public FramesSequenceAnimation createSplashAnim(ImageView imageView, int[] n) {
return new FramesSequenceAnimation(imageView, n);
}
/**
* AnimationPlayer. Plays animation frames sequence in loop
*/
public class FramesSequenceAnimation {
private int[] mFrames; // animation frames
private int mIndex; // current frame
private boolean mShouldRun; // true if the animation should continue running. Used to stop the animation
private boolean mIsRunning; // true if the animation currently running. prevents starting the animation twice
private SoftReference<ImageView> mSoftReferenceImageView; // Used to prevent holding ImageView when it should be dead.
private Handler mHandler;
private int mDelayMillis;
private OnAnimationStoppedListener mOnAnimationStoppedListener;
private Bitmap mBitmap = null;
private BitmapFactory.Options mBitmapOptions;
public FramesSequenceAnimation(ImageView imageView, int[] frames) {
mHandler = new Handler();
mFrames = frames;
mIndex = -1;
mSoftReferenceImageView = new SoftReference<ImageView>(imageView);
mShouldRun = false;
mIsRunning = false;
mDelayMillis = 50;
imageView.setImageResource(mFrames[0]);
// use in place bitmap to save GC work (when animation images are the same size & type)
if (Build.VERSION.SDK_INT >= 11) {
Bitmap bmp = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
int width = bmp.getWidth();
int height = bmp.getHeight();
Bitmap.Config config = bmp.getConfig();
mBitmap = Bitmap.createBitmap(width, height, config);
mBitmapOptions = new BitmapFactory.Options();
// setup bitmap reuse options.
mBitmapOptions.inBitmap = mBitmap;
mBitmapOptions.inMutable = true;
mBitmapOptions.inSampleSize = 1;
}
}
private int getNext() {
mIndex++;
if (mIndex == mFrames.length){
mIndex = mIndex - 1;
mShouldRun = false;
}
return mFrames[mIndex];
}
/**
* Starts the animation
*/
public synchronized void start() {
mShouldRun = true;
if (mIsRunning)
return;
Runnable runnable = new Runnable() {
#Override
public void run() {
ImageView imageView = mSoftReferenceImageView.get();
if (!mShouldRun || imageView == null) {
mIsRunning = false;
if (mOnAnimationStoppedListener != null) {
mOnAnimationStoppedListener.onAnimationStopped();
}
return;
}
mIsRunning = true;
mHandler.postDelayed(this, mDelayMillis);
if (imageView.isShown()) {
int imageRes = getNext();
if (mBitmap != null) { // so Build.VERSION.SDK_INT >= 11
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeResource(imageView.getResources(), imageRes, mBitmapOptions);
} catch (Exception e) {
e.printStackTrace();
}
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(imageRes);
mBitmap.recycle();
mBitmap = null;
}
} else {
imageView.setImageResource(imageRes);
}
}
}
};
mHandler.post(runnable);
}
/**
* Stops the animation
*/
public synchronized void stop() {
mShouldRun = false;
}
}
}
Can anyone explain me why and tell me how to fix it? I already added
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
to my manifest file.
It might help to be sure that you are not keeping references to unneeded images. This is happening because you probably have the "standard" memory heap of 32MB or something similar (maybe 64MB or maybe 16MB). If you consider that most images are 5MB or more, it's not surprising you are out of memory.
You can increase the heap size using android:largeHeap="true" like this:
How to increase heap size of an android application?

Android Screen shots handler

I have create the Handler inside the activity onCreate method. This Hanlder is responsible to take screen shots after 10 seconds. Inside the run method I have used while(flag==true) and screen the capture util flag==false, But this stuck my activity. I can not able to work. And it take the screen shot over again and again of same image because of actvity is stuck.
How I can work with my screen and what I am doing handler take the screen shot after 10 seconds?
The while loop stuck my app.
It Take picture but I am not able to work with my activity.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
flag = true;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
while (flag == true) {
String SCREENSHOTS_LOCATIONS = Environment
.getExternalStorageDirectory().toString() + "/re/";
// Get root view
View view = getWindow().getDecorView().getRootView();
// Create the bitmap to use to draw the screenshot
final Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
// Get current theme to know which background to use
final Theme theme = getTheme();
final TypedArray ta = theme
.obtainStyledAttributes(new int[] { android.R.attr.windowBackground });
final int res = ta.getResourceId(0, 0);
final Drawable background = getResources().getDrawable(res);
// Draw background
background.draw(canvas);
// Draw views
view.draw(canvas);
FileOutputStream fos = null;
try {
final File sddir = new File(SCREENSHOTS_LOCATIONS);
if (!sddir.exists()) {
sddir.mkdirs();
}
fos = new FileOutputStream(SCREENSHOTS_LOCATIONS + x
+ ".jpg");
x++;
if (fos != null) {
if (!bitmap.compress(Bitmap.CompressFormat.JPEG,
90, fos)) {
Log.d("ScreenShot", "Compress/Write failed");
}
fos.flush();
fos.close();
}
} catch (Exception e) {
}
}
}
}, 1000);
}
Maybe try using an AsyncTask or other thread. The postDelayed() function attaches to the main UI thread and locks up your app until run() is finished (which never happens because flag never equals false so the while loop becomes infinite?).
Here is an example using the ScheduledThreadPoolExecutor:
private ScheduledThreadPoolExecutor exec = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
flag = true;
exec = new ScheduledThreadPoolExecutor(5);
long interval = (long) 10; // 10 seconds for you
exec.scheduleAtFixedRate(new savePicTask(), 0, interval, TimeUnit.SECONDS);
}
class savePicTask implements Runnable {
#Override
public void run() {
while (flag == true) {
String SCREENSHOTS_LOCATIONS = Environment
.getExternalStorageDirectory().toString() + "/re/";
// Get root view
View view = getWindow().getDecorView().getRootView();
// Create the bitmap to use to draw the screenshot
final Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
// Get current theme to know which background to use
final Theme theme = getTheme();
final TypedArray ta = theme
.obtainStyledAttributes(new int[] { android.R.attr.windowBackground });
final int res = ta.getResourceId(0, 0);
final Drawable background = getResources().getDrawable(res);
// Draw background
background.draw(canvas);
// Draw views
view.draw(canvas);
FileOutputStream fos = null;
try {
final File sddir = new File(SCREENSHOTS_LOCATIONS);
if (!sddir.exists()) {
sddir.mkdirs();
}
fos = new FileOutputStream(SCREENSHOTS_LOCATIONS + x
+ ".jpg");
x++;
if (fos != null) {
if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos)) {
Log.d("ScreenShot", "Compress/Write failed");
}
fos.flush();
fos.close();
}
} catch (Exception e) {
}
}
}
}
EDIT 1:
This code works for me except I am using
numberOfSeconds = 0.5;
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(5);
long interval = (long) (1000* numberOfSeconds); // numberOfSeconds = 10 for you
exec.scheduleAtFixedRate(new savePicTask(), 0, interval, TimeUnit.MILLISECONDS);
And instead of taking a screenshot I am taking a picture with the camera. So I'm not sure why it's not working for you.

Thread is to be running if surfaceDestroyed() is called when home button is pressed

I am new to android Surfaceview implementation. I am developing RDP client application in android3.0. I getting the image stream from socket, drawing this image to surface using Surfaceview and Thread.
The sample code of surface view:
class mySurfaceView extends SurfaceView implements SurfaceHolder.Callback
{
private TutorialThread _thread;
Canvas c=null;
public mySurfaceView(Context context)
{
super(context);
getHolder().addCallback(this);
_thread = new TutorialThread(getHolder(), this);
matrix= new Matrix();
m = new float[9];
paint = new Paint();
}
public void surfaceCreated(SurfaceHolder arg0) {
//setWillNotDraw(false) ;
Log.e("surfaceCreated","surfaceCreated");
if(_thread==null ){
Log.e("_thread.created","thread created");
_thread = new TutorialThread(getHolder(),this);
_thread.setRunning(true);
_thread.start();
// <-- added fix
}else {
Log.e("_thread.getState()",_thread.getState()+"");
_thread.setRunning(true); //original code
_thread.start(); //original code
}
}
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.e("surfaceDestroyed","surfaceDestroyed");
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
}
class TutorialThread extends Thread
{
private SurfaceHolder _surfaceHolder;
private mySurfaceView _panel;
private boolean _run = false;
private InputStream is;
private Socket socket;
Bitmap resizeBmp;
public TutorialThread(SurfaceHolder surfaceHolder,mySurfaceView panel)
{
Log.e("TutorialThread","TutorialThread-->Constructor");
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
#Override
public void run()
{
Log.e("TutorialThread","TutorialThread-->run()");
try
{
socket = new Socket("172.19.1.144", 4444);
is = socket.getInputStream();
DataInputStream inputputStream = new DataInputStream(is);
//long time = System.currentTimeMillis();
int i=0;
while (socket.isConnected() )
{
Log.e("tutorial thread","While running");
c = null;
i++;
if(i==10){
System.gc();
i=0;
}
Log.e("BEFORE","BEFORE");
synchronized (_surfaceHolder)
{
Log.e("AFTER","AFTER");
ByteBuffer inputHeaderBuffer = ByteBuffer.allocate(20);
inputHeaderBuffer.order(ByteOrder.LITTLE_ENDIAN);
inputputStream.readFully(inputHeaderBuffer.array());
SurfaceViewPinchZoom.serverWidth=inputHeaderBuffer.getInt();
SurfaceViewPinchZoom.serverHeight=inputHeaderBuffer.getInt();
//Log.e("serverWidth","serverWidth "+ SurfaceViewPinchZoom.serverWidth+"serverHeight===="+SurfaceViewPinchZoom.serverHeight);
SurfaceViewPinchZoom.left=inputHeaderBuffer.getInt();
SurfaceViewPinchZoom.top=inputHeaderBuffer.getInt();
int dataLength = inputHeaderBuffer.getInt();
ByteBuffer imageDataCompress = ByteBuffer.allocate(dataLength);
imageDataCompress.order(ByteOrder.LITTLE_ENDIAN);
inputputStream.readFully(imageDataCompress.array());
byte[] imagedata = new byte[imageDataCompress.remaining()];
imageDataCompress.get(imagedata);
//Decompress the image
//Log.e("imagedata.length::::::::::",imagedata.length+"");
// Create the decompressor and give it the data to compress
Inflater decompressor = new Inflater();
decompressor.setInput(imagedata);
// Create an expandable byte array to hold the decompressed data
ByteArrayOutputStream bos = new ByteArrayOutputStream(imagedata.length);
// Decompress the data
byte[] buf = new byte[1024];
while (!decompressor.finished()) {
try {
int count = decompressor.inflate(buf);
bos.write(buf, 0, count);
} catch (DataFormatException e) {
}
}
try {
bos.close();
} catch (IOException e) {
}
// Get the decompressed data
byte[] decompressedData = bos.toByteArray();
/
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
// Log.e("decompressedData.length::::::::::",decompressedData.length+"");
/*SurfaceViewPinchZoom.*/bmp = BitmapFactory.decodeByteArray(decompressedData, 0,decompressedData.length,options);
options.inDither=true;
/*scaleX=(float)screen_width/bmp.getWidth();
scaleY=(float)screen_height/bmp.getHeight();
matrix.setScale(scaleX, scaleY);*/
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, screen_width, screen_height);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
/*SurfaceViewPinchZoom.*/bmp= BitmapFactory.decodeByteArray(decompressedData, 0,decompressedData.length,options);
bmp=BitmapFactory.decodeByteArray(decompressedData, 0,decompressedData.length,options);
c = _surfaceHolder.lockCanvas();
c.drawBitmap(bmp, matrix, paint);
//draw(c);
//postInvalidate();
onDraw(c);
inputHeaderBuffer.clear();
imageDataCompress.clear();
inputHeaderBuffer = null;
imageDataCompress = null;
imagedata = null;
}
if (c != null)
{
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
catch (ArrayIndexOutOfBoundsException ae)
{
ae.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
finally {
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
private int calculateInSampleSize(Options options, int screen_width,
int screen_height) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > screen_height || width > screen_width) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)screen_height);
} else {
inSampleSize = Math.round((float)width / (float)screen_width);
}
}
return inSampleSize;
}
}
}
The problems are
1) if I press home button then surfaceDestroyed() is called and thread is terminated.
But I need to continue the Thread and update the images(input stream from socket) after open the application from home button is pressed.
2) if I call the activity on doubletap event as child activity, surfaceDestroyed() is called and Thread is terminated.
Where I need to continue the images display after returning from child activity.
In both the case I am getting exception as java.lang.IllegalThreadStateException: Thread already started.
Could please help how to run the same thread without terminating on home button is pressed or another child activity is called?
Thanks & Regards
Yamini

Drawing dynamic elements onto a normal xml layout

I've been trying to figure this out for a while now... I need to place marks over top of a seekBar to show the user places that they bookmarked in the past. The data is stored in xml. The problem is making the little ovals appear over the seekBar... It just doesn't work...
Here's my code:
public class seekMark extends View {
private int seekLength; // in pixels
private int seekLeftPad; // in pixels
private int seekBottomPad; // in pixels
private int trackLength; // in ms
private float pxOverMs; // in px/ms
ShapeDrawable lmark;
private seekMark instance;
public seekMark(Context context){
super(context);
instance = this;
seekLength = progressBar.getWidth();
seekLeftPad = progressBar.getPaddingLeft();
seekBottomPad = progressBar.getBottom();
trackLength = player.getDuration();
pxOverMs = pxPerMs();
lmark = new ShapeDrawable(new OvalShape());
}
private float pxPerMs(){
return ((float) seekLength)/((float) trackLength);
}
private int[] markPxList() throws XmlPullParserException, IOException {
int bmStartTime = 0;
String bmNames[] = bmNameList(xmlPath);
int[] bmPos = new int[bmNames.length];
for(int i=0; i < bmNames.length; i++){
bmStartTime = getBookmark(xmlPath, bmNames[i]);
bmPos[i] = (int) (bmStartTime * pxOverMs);
}
return (bmPos);
}
public void markPlace() throws XmlPullParserException, IOException {
int y = seekBottomPad;
int x = 0;
int bmPos[] = markPxList();
for(int i = 0; i < bmPos.length; i++){
x = bmPos[i] + seekLeftPad;
lmark = new ShapeDrawable();
lmark.getPaint().setColor(0xff74AC23);
lmark.setBounds(x, y, x + 1, y + 1);
instance.invalidate();
}
}
protected void onDraw(Canvas canvas) {
lmark.draw(canvas);
}
}
It's called from onCreate using this code. I call it using in another thread to avoid the problem where the dimensions of progressBar aren't yet set in onCreate.
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == 1){ // if landscape
final Runnable runner = new Runnable() {
public void run() {
seekMark seekMarks = new seekMark(context);
try {
seekMarks.markPlace();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// runs in another thread to avoid the problem with calling
// seekMark directly from onCreate
}
};
handler.postDelayed(runner, 1000);
}
The program crashes whenever I try to call seekMark.markPlace()... I'm trying to draw this over top of my layout main.xml.
im not sure if this is what you are trying to do.
Customize Seekbar
this seems to be similar while the approach is different.

Android: custom view is too slow?

I have a custom view with a lot of png images on it(For every three characters an image). but it is too slow on drawing and scrolling.
It is my code for custom view:
public class Textview extends View
{
private String m_szText;
Context ctx;
Paint mTextPaint;
private Canvas canva;
Bitmap b ;
public Textview(Context context)
{
super(context);
ctx = context;
mTextPaint= new Paint();
mTextPaint.setTypeface(m_tTypeface);
mTextPaint.setStyle(Paint.Style.FILL);
}
public void SetText(String newtext) {
m_szText = newtext;
text(newtext);
this.invalidate();
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(text(canvas,m_szText));
}
Canvas text(Canvas canvas,String txt)
{
int left = 400;
int top = 0;
try {
for(int i=0;i<txt.length();i=i+3)
{
String adres = "glyph/" + txt.substring(i, i+3) + ".png";
Bitmap btm = getBitmapFromAsset(adres);
if(left <= 5)
{left = 400;top += btm.getHeight();}
else
left = left - btm.getWidth();
canvas.drawBitmap(btm, left ,top,mTextPaint);
}
} catch (IOException e) {
canvas.drawText(e.toString(), 50, 50, mTextPaint);
}
return canvas;
}
private Bitmap getBitmapFromAsset(String strName) throws IOException
{
AssetManager assetManager = ctx.getAssets();
InputStream istr = assetManager.open(strName);
Bitmap bitmap = BitmapFactory.decodeStream(istr);
return bitmap;
}
}
How can I speed up my custom view? I think I must to create bitmap of all images once. but how to?
thanks in advance!
You are loading and decoding several bitmaps on every draw. You need to load the bitmaps ahead of time, once and then draw them.
You can use Thread to speed up process, and there are two way to use thread
1)Implementing Runnable that override void run(){}
2)or use Thread th=new Thread(new Runnable(){void run(){}
})
The following should help. just outline of what can be done.
static HashMap<String, Bitmap> mBitmaps = new HashMap<String, Bitmap>();
public void SetText(String newtext) {
m_szText = newtext;
makeBitmap();
this.invalidate();
}
void makeBitmap()
{
for(int i=0; i<m_szText.length(); i=i+3)
{
String adres = "glyph/" + m_szText.substring(i, i+3) + ".png";
Bitmap btm = null;
if (!mBitmaps.containsKey(adres)) {
btm = getBitmapFromAsset(adres);
mBitmaps.add(adres , btm);
} else {
btm = (Bitmap)mBitmaps.get(adres);
}
length += btm.getWidth(); // considering only single line.
}
// create a new blank Bitmap of height and 'length' and assign to member.
mTextBitmap = Bitmap.createBitmap(length, height, Bitmap.Config.ARGB_8888);
// in for loop draw all the bitmaps on mTextBitmap just like you did on canvas in ur code.
}

Categories

Resources