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.
Related
I have a picture that contains 2 icons at the bottom of the picture i'm already croping the picture to get only the buttom and comparing it with the icon picture opencv temple image detecter it works perfectly when the icon is there but the problem is when i delete the icon still the rectangle appears and it appears in wrong place all i want if there is a match show the rectangle if there is not don't show it
here is my code
public class Test123 extends AppCompatActivity {
ImageView a,b,c;
String resultImgPath,baseDir,lol;
Button x;
private static final String TAG = "Test123";
String aa,bb;
static {
if(!OpenCVLoader.initDebug()){
Log.e(TAG, "OpenCV not loaded");
} else {
Log.e(TAG, "OpenCV loaded");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test123);
System.loadLibrary("opencv_java3");
a = (ImageView)findViewById(R.id.imageView);
b = (ImageView)findViewById(R.id.imageView2);
c = (ImageView)findViewById(R.id.imageView3);
x = (Button) findViewById(R.id.button);
baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
resultImgPath = baseDir+"/Test/result.jpg";
aa = baseDir+"/Test/d.jpg";
bb = baseDir+"/Test/dd1.jpg";
lol = baseDir+"/Test/c.jpg";
x.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Bitmap bmImg = BitmapFactory.decodeFile(aa);
int fromHere = (int) (bmImg.getHeight() * 0.06);
final Bitmap croppedBitmap = Bitmap.createBitmap(bmImg, (int) (bmImg.getWidth() * 0.3), (int) (bmImg.getHeight() * 0.94), (int) (bmImg.getWidth() * 0.6), fromHere);
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/Test");
myDir.mkdirs();
String fname = "c.jpg";
File file = new File(myDir, fname);
if (file.exists())
file.delete();
try {
FileOutputStream out = new FileOutputStream(file);
croppedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
a.setImageBitmap(croppedBitmap);
Bitmap bmImg2 = BitmapFactory.decodeFile(bb);
b.setImageBitmap(bmImg2);
matchingDemo(lol, bb, resultImgPath, Imgproc.TM_SQDIFF);
}
});
}
public void matchingDemo(String imgPath,String templatePath,String resPath, int matchType){
// to read the entered image from its path and make a mat object
Mat img = Imgcodecs.imread(imgPath);
Mat templ = Imgcodecs.imread(templatePath);
// Create the result matrix
int result_cols = img.cols() - templ.cols() + 1;
int result_rows = img.rows() - templ.rows() + 1;
Mat result = new Mat(result_rows, result_cols, CvType.CV_8UC3);
// performing matching and do normalization
Imgproc.matchTemplate(img, templ, result, matchType);
int type = Imgproc.THRESH_TOZERO;
Imgproc.threshold(result, result, 0.8, 1., type);
Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
// / finding the best match from minMaxLoc
Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
double bb = mmr.maxVal;
Log.e("hey",bb+"");
Point matchLoc;
if (matchType == Imgproc.TM_SQDIFF || matchType == Imgproc.TM_SQDIFF_NORMED) {
matchLoc = mmr.minLoc;
} else {
matchLoc = mmr.maxLoc;
}
// draw a rectangle on searched object
Imgproc.rectangle(img, matchLoc, new Point(matchLoc.x + templ.cols(),
matchLoc.y + templ.rows()), new Scalar(0, 255, 0));
// store the result image here
Imgcodecs.imwrite(resPath, img);
Mat image = new Mat();
image =Imgcodecs.imread(resPath);
Bitmap bm = Bitmap.createBitmap(image.cols(),image.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(image, bm);
c.setImageBitmap(bm);
image.release();
}
}
EDIT
i know that i need something here
if(......................)
Imgproc.rectangle(img, matchLoc, new Point(matchLoc.x + templ.cols(),
matchLoc.y + templ.rows()), new Scalar(0, 255, 0));
}
I tried to put minVal inside the if block but every picture gives me different numbers i tried with normalize and without it i can put the right number on 1 picture but other picture gives me different numbers so it is not detecting at all if the icon is visible or if it is not it givin the same issue drawing in wrong place i just need 1 number or something to draw if it is there to not draw if there is no match i don't want to have value if there is no match
Originally my first bitmap object I get from previous activity, and compare with another bitmap in same activity. I done bitmap comparison on button's click (called Next), but I faced one problem. When I click on button(Next) then one time bitmap object change after comparison. I want to continously change bitmap object using button's click(Next). Below is my code which I has been done.
//I use bundle extra for getting bitmap object from previous activity
Bundle extras = getIntent().getExtras();
byte[] byteArray = extras.getByteArray("picture");
Bitmap bmp = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
btn_next = (Button) findViewById(R.id.btn_next);
btn_next.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Bitmap img_A = BitmapFactory.decodeResource(getResources(), R.drawable.img_a);
Bitmap img_B = BitmapFactory.decodeResource(getResources(), R.drawable.img_b);
Bitmap img_C = BitmapFactory.decodeResource(getResources(), R.drawable.img_c);
Bitmap img_D = BitmapFactory.decodeResource(getResources(), R.drawable.img_d);
if(imagesAreEqual(bmp, img_A)){
bitmap = img_B.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(bitmap);
}
else if(imagesAreEqual(bmp, img_B)){
bitmap = img_C.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(bitmap);
}
else if(imagesAreEqual(bmp, img_C)){
bitmap = img_D.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(bitmap);
}
else{
Toast.makeText(getApplicationContext(), "Not Matched", Toast.LENGTH_SHORT).show();
}
}
});
And this is imagesAreEqual(),
boolean imagesAreEqual(Bitmap i1, Bitmap i2)
{
if (i1.getHeight() != i2.getHeight())
return false;
if (i1.getWidth() != i2.getWidth()) return false;
for (int y = 0; y < i1.getHeight(); ++y)
for (int x = 0; x < i1.getWidth(); ++x)
if (i1.getPixel(x, y) != i2.getPixel(x, y)) return false;
return true;
}
I think I don't really get you point with this question, but I think you should try to get the new byteArray[] for the bmp after you are through with one loop.
Or can you somehow call this thread (what then is no longer necessary) whenever the byteArray changes, so you don't have to check 30 times/s, what might really save you some battery.
Or, if that is not possible check like 30 times/s if the byteArray has changed, and only if, check if it is the same as one of the others.
but I don't really know if I really got your problem, so just comment if not.
Edit: you wanted some code, so here comes:
public class myActivity implements Runnable{
private Thread thread;
public boolean running = false;
private Bitmap oldbmp;
Bundle extras = getIntent().getExtras();
byte[] byteArray = extras.getByteArray("picture");
public void setRunning(boolean setRunning){
running = setRunning;
}
public void run(){
while(running){
//Start Time
long startTime = System.currentTimeMillis();
byte[] byteArray = extras.getByteArray("picture");
Bitmap bmp = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
if(!bmp.equals(oldbmp){
if(imagesAreEqual(bmp, img_A)){
bitmap = img_B.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(bitmap);
} else if(imagesAreEqual(bmp, img_B)){
bitmap = img_C.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(bitmap);
} else if(imagesAreEqual(bmp, img_C)){
bitmap = img_D.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(bitmap);
} else if(imagesAreEqual(bmp, img_D)){
bitmap = img_D.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(bitmap);
}
//End Time
long endTime = System.currentTimeMillis();
if (endTime -startTime < 1000/30){
try
{
Thread.sleep(1000/2 -(endTime -startTime));
} catch (InterruptedException e){}
}
}
}
}
}
Credits to #TomTsagk
so here's some code what should work if added correctly.
It checks every half a second if the bmp has changed, and if, looks if there is one of the bitmaps looking the same, but I really don't know what that would be useful for. If there's something else I should add or change, just ask.
if you want to continuously change the bitmap when you click the button you can create a new thread and do it like that:
make your current activity implement Runnable
public class myActivity extends Activity implements Runnable
{
private Thread thread;
private boolean running = false;
//...
}
then create a method inside the activity like this:
public void run()
{
while(running)
{
//Start Time
long startTime = System.currentTimeMillis();
if(imagesAreEqual(bmp, img_A)){
bitmap = img_B.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(bitmap);
}
else if(imagesAreEqual(bmp, img_B)){
bitmap = img_C.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(bitmap);
}
else if(imagesAreEqual(bmp, img_C)){
bitmap = img_D.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(bitmap);
}
//End Time
long endTime = System.currentTimeMillis();
if (endTime -startTime < 1000/30)
try
{
Thread.sleep(1000/30 -(endTime -startTime));
} catch (InterruptedException e){}
}
}
Also when the button is clicked apply the following:
public void onClick(View v) {
// TODO Auto-generated method stub
Bitmap img_A = BitmapFactory.decodeResource(getResources(), R.drawable.img_a);
Bitmap img_B = BitmapFactory.decodeResource(getResources(), R.drawable.img_b);
Bitmap img_C = BitmapFactory.decodeResource(getResources(), R.drawable.img_c);
Bitmap img_D = BitmapFactory.decodeResource(getResources(), R.drawable.img_d);
thread = new Thread(this);
running = true;
thread.start();
}
This will make your code check the image 30 times each second, if you want to change how fast it checks change the "1000/30" on the run() method (it counts in milliseconds)
Although I'm not sure I recommend something like this because checking so many bitmaps continuously is very cpu intensive, but if it solves your problem I guess it's worth it.
Also I'm not sure I understand your problem 100%, you can also try to run the check just once each time a bitmap changes, if that's the case drop a comment and I will edit my answer.
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
Maybe a simple question but i have an activity that retrieves a bitmap(camerashot) from a folder on the sdcard. The activity's custom view extends viewgroup. i'd like to add the bitmap to the view then add that view to the view group then display. eventually there will be multiple views added in this way. what are the best practices for this? for example would you get the activity to get the bitmap first, then in the viewgroup file access that bitmap with the following.
bitmap bm = (ActivityName()getContext()).methodToGetBitmap();
The bitmap can be added to a view, which inturn can be addeded to the viewgroup then displayed. thanks
[update] activity
public class HorizontalPagerActivity extends Activity {
private static final String TAG = "*********hpActivity";
private Context mContext = this;
File tempFile;
byte [] imageArray;
private Bitmap b = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.hpview);
final ViewGroup viewgroup = (ViewGroup)findViewById(R.id.hpview);
tempFile = new File(Environment.getExternalStorageDirectory().
getAbsolutePath() + "/"+"image.jpeg");
imageArray = new byte[(int)tempFile.length()];
try{
InputStream is = new FileInputStream(tempFile);
BufferedInputStream bis = new BufferedInputStream(is);
DataInputStream dis = new DataInputStream(bis);
int i = 0;
while (dis.available() > 0 ) {
imageArray[i] = dis.readByte();
i++;
}
dis.close();
} catch (Exception e) {
e.printStackTrace();
}
Bitmap bm = BitmapFactory.decodeByteArray(imageArray, 0, imageArray.length);
// Bitmap b = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
b = bm.copy(bm.getConfig(), true);
if(b == null){
Log.e(TAG, "b = null");
}else{
Log.e(TAG, "b = not null");
}
Canvas canvas = new Canvas(b);
Log.e(TAG, "canvas created");
View view = new View(this);
Log.e(TAG, "view created");
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
view.setLayoutParams(lp);
view.draw(canvas);
viewgroup.addView(view);
Log.e(TAG, "view added to viewgroup");
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
viewgroup.postInvalidate();
}
});
Log.e(TAG, " inval called on viewgroup");
Log.e(TAG, "no of chidren = "+viewgroup.getChildCount());
}
}
the activity's view ia a viewgroup. so this is the parent view. the activity preprocesses the bitmap, creates and adds the views dynamically. it also calls invalidate on the parent viewgroup using runOnUiThread().
Get the parent view, and then dynamically append views to it.
Of course the activity would have to do the preprocessing and also append those views to the view group. Ideally this should be done in an AsyncTask, so that your activity can handle its current function. When the AsyncTask finshes, either use a handler to update the views/append or just run the update on the ui thread (runOnUIThread(...)).
I just needed to change the view to an ImageView and the above code worked. so i think Jox's advice is correct.... Get the parent Viewgroup then dynamically add views to it. if an image then use imageview.
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.
}