I start with Android and Java, and my English is not very good (sorry).
I'm doing a application which compare 2 pictures taking by the camera and return a float value = a ratio of identical pixels in the 2 pictures.
public static float comparePic(String img_1, String img_2){
Bitmap bitmap1 = BitmapFactory.decodeFile(img_1);
Bitmap bitmap2 = BitmapFactory.decodeFile(img_2);
int equ = 0;
//get one height and one width because we assume that pictures have always same sizes
int h = bitmap1.getHeight();
int w = bitmap1.getWidth();
for(int y=0;y<h;y++){
for (int x=0;x<w;x++){
int pixel1 = bitmap1.getPixel(x,y);
int pixel2 = bitmap2.getPixel(x,y);
//alpha doesn't matter, they're jpg
int redValue1 = Color.red(pixel1);
int redValue2 = Color.red(pixel2);
int greenValue1 = Color.green(pixel1);
int greenValue2 = Color.green(pixel2);
int blueValue1 = Color.blue(pixel1);
int blueValue2 = Color.blue(pixel2);
if (redValue1==redValue2 && greenValue1==greenValue2 && blueValue1==blueValue2){
equ++;
}
}
}
return (float)equ/(h*w);
}
When I execute it, I have this message : "I/Choreographer﹕ Skipped 730 frames! The application may be doing too much work on its main thread."
So I tried to do it with a thread, but I'm always failing because I don't know how to return the value.
Futhermore, by skipping frames I guess, the ratio is not correct.
I know that it's an asynchonous work, so what can I do ?
Thanks !
You can simply add a public (setter-)method in your main class (or wherever you need the value).
When your async thread is done call the method with equ as the parameter.
You obviously need to care about thread-safety so consider making the method sychronized.
You should give a try to AsyncTask. It's a class specifically prepared for background processing. It has some drawbacks (it's not good idea to do networking with AsyncTask), but for some picture comparison stuff it is a great tool.
Define an Asynctask with a interface and implement that interface in the main Activity.
That way you can notify that host activity that the background asynctask has completed.
Related
I am trying to create an animation for my game. I am trying to make an animation of a coin flip that will stop under certain conditions.
So far I have tried to change an image view multiple times within one method and using thread.sleep to delay the transition between the pictures.
Using 12 different images I am now trying to make it so the alpha of the first image will set to 0 and the second image will set to one, the the second image will set to 0 and the third will set to 1, etc...
The way I am currently trying to do it is by putting images inside of an array of ImageViews and then calling them sequentially.
setContentView(R.layout.coin_flip_screen);
for(int i = 0; i < 4; i++){
headsTails[i].animate().alpha(0).setDuration(100);
headsTails[i+1].animate().alpha(1).setDuration(100);
try {
Thread.sleep(100);
} catch (Exception e) {
}
}
final int size = imageView.length;
final int animTime = 300;
final Handler animationHandler = new Handler();
Runnable animationRunnable = new Runnable() {
int i = 0;
#Override
public void run() {
if(i == size-1){
animationHandler.removeCallbacks(this);
return;
}
imageView[i++].animate().alpha(0f).setDuration(animTime).start();
imageView[i].animate().alpha(1f).setDuration(animTime).start();
animationHandler.postDelayed(this, animTime);
}
};
animationHandler.post(animationRunnable);
This code will iterate through all your imageviews in the array and stop itself once all the images are consumed.
Play along with your animTime variable until you get the perfect animation effect. Ideally it should be around 300 to 500 ms.
I will personally not use array of imageviews to create this effect as
it will eat up the memory. There are many more efficient ways to do
the coin flip animation, which you can google when you get time.
This should fix it
headsTails[i].animate().alpha(0).setDuration(100).start();
There I have a loop:
public void updateDrawee(View view) {
if (begin) {
begin = false;
for (int i = 0; i < 5; i++) {
CloseableReference<CloseableImage> reference = createBitmapRefer(i);
Log.i("reference", reference+"");
imgList.add(reference);
}Log.i("imgList", imgList.toString());Log.i("imgList.0", imgList.get(0)+"");
}
//...some code
}
and the method createBitmapRefer(int count) follow:
public CloseableReference<CloseableImage> createBitmapRefer(int count) {
ImagePipeline pipeline = Fresco.getImagePipeline();
int[] drawableIds = {R.drawable.alpha1, R.drawable.alpha2,
R.drawable.alpha3, R.drawable.alpha4, R.drawable.alpha5};
ImageRequest levelRequest
= ImageRequestBuilder.newBuilderWithResourceId(drawableIds[count])//++
.setProgressiveRenderingEnabled(true)//逐行加载
.build();
CloseableReference<CloseableImage> bmpReference = null;
DataSource<CloseableReference<CloseableImage>> dataSource
= pipeline.fetchImageFromBitmapCache(levelRequest, this);
try {
if (!dataSource.hasResult()) {
dataSource = pipeline.fetchDecodedImage(levelRequest, this);
}
//count %= 5;
Log.i("dataSource has result", dataSource.hasResult() +"");
Log.i("dataSource fail?", dataSource.hasFailed() + "");
bmpReference = dataSource.getResult();
Log.i("bmpRefer", bmpReference+"");
if (bmpReference != null) {
CloseableReference<CloseableImage> returnRef;
returnRef = bmpReference.clone();
return returnRef;
}else {
return null;
}
}finally {
dataSource.close();
CloseableReference.closeSafely(bmpReference);
}
}
when I debug, if i click step into and see the code step by step, it will return a CloseableReference just as I want, and the imgList(its a ArrayList) can get the element too.BUT if I step over the for loop, it return nothing!
Is there any different between keep looking at it or not???
the watches show elements in imgList, when index=1 and 4, I clicked step into.
and the logcat show what Log.i() print.
Or because I have not use this classCloseableReference in Standardized way?
Let me try to explain what happens here.
You are not using Fresco in the intended way. I will step back for a moment and strongly suggest that you use SimpleDraweView if you just need to display images. If however you really need the underlying bitmap, you can get it from the ImagePipeline in way similar to what you already doing, but with one key difference. Fetching images happens asynchronously. What that means is that you can't just do dataSource = pipeline.fetchDecodedImage(...) and then immediately dataSource.getResult. If the image was not found in the memory cache, getResult will just return null. What you need to do instead is to subscribe to the DataSource as explained in the Fresco documentation. I strongly suggest that you read those few chapters about ImagePipeline if you intend to use it directly. Otherwise you may cause your app to leak the memory or to crash because of rendering recycled bitmap.
What you see in debugger is exactly what I described above. The array of size 5 looks like this:
0 = null,
1 = CloseableReference#4908,
2 = null,
3 = null,
4 = CloseableReference#5231
The AndroidStudio UI just hides the null entries for brevity. You can turn this off if you don't like it by right-clicking there and opening options. The reason you get something for 1 and 4 is because the image has been found in the bitmap memory cache and was retrieved from it immediately. The reason you get null for 0, 2 and 3 is because the image has not been loaded yet. Fresco might need to download the image, and even if it is already downloaded and in the disk cache, it may need to decode the image. All of this takes some time and is not instantaneous. That's why you need to subscribe your callback and ImagePipeline will notify you when the image is ready.
I have been trying to figure out how to find the height and width of the screen in android. i have found a way to get it but I dont know how to call the getScreenWidth and getScreenHeight to put values into my int height and int width?
public class Player {
public int across;
public int upDown;
public static int getScreenWidth(Context c) {
DisplayMetrics dmetrics = new DisplayMetrics();
((Activity) c).getWindowManager().getDefaultDisplay()
.getMetrics(dmetrics);
return dmetrics.widthPixels;
}
// Get screen height
public static int getScreenHeight(Context c) {
DisplayMetrics dmetrics = new DisplayMetrics();
((Activity) c).getWindowManager().getDefaultDisplay()
.getMetrics(dmetrics);
return dmetrics.heightPixels;
}
public Player() {
int width = dmetrics.widthPixels;
int height = dmetrics.heightPixels;
int rectSide = 1000;
//across = startPosX;
//upDown = startPosY;
}
i am trying to get it by using int width = dmetric.widthPixels; but this obviously isnt the way to call the getScreenWidth. Im pretty bad at this stuff, so any help would be great.
You can refer to Here
or Here
for your answer.
Ps - sorry , I can't comment as I am a beginner so I wrote the answer which should rather be a comment.
I know, really what im asking is how do i call this get method i have created to set values for width and height? – Phill
If you are in an Activity when you wish to call these static methods you could call them this way:
int width = Player.getScreenWidth(this);
int height = Player.getScreenHeight(this);
If you're not in an activity you'll need to know one and pass it instead of this.
Also be aware that, because of the cast, if you pass something that is a Context but not an Activity it won't work and you won't know it until run time.
I am making a simple sequence from randomly generated numbers. Each number will show an image linked to it.
for example,
the value 1 will show a picture of a cat.
value 2 a dog
and value 3 a mouse.
Each image has it's own dedicated imageview, the layout looks like this by default, i.e image views that store black until it's number is called:
Each time the sequence increments. so on the second run two images will show, on the third 3 will show and so on.
The problem I am having is that all the images show at once. So for sequence one just the one image flashes (which is what I want). but on the second run both images show at once together instead of showing the first image then the second.
So to clarify let's say on the four runs the stored array is 1,2,3,3 I would want
image 1 to show, and disappear.then
image 2 show and disappear. then
image 3 show and disappear
and then image 3 to show and disappear.
But what I actually get is on the fourth run 1,2&3 will show at once and disappear at the same time together. How can I break this up to achieve what I want. I have tried many methods and the same result happens. I can't get my head around this problem.
Here is my code:
ArrayList<Integer> stored_vals = new ArrayList<Integer>();
public void Gen() {
int i=0 ;
Random rand = new Random();
int rndInt = rand.nextInt(3)+ 1 ;
list.add(rndInt);
int totalElements = list.size();
Log.d("LOOK", Integer.toString(rndInt));
Log.i("VALUE LIST ", list.toString()+" <<<<LIST HERE");
while(i < totalElements) {
retval =list.get(i);
Log.d("RETVAL", Integer.toString(retval));
String imgName = "flash" + retval;
int id = getResources().getIdentifier(imgName, "drawable", getPackageName());
if (retval==1){
Cat.setImageResource(id);
Reset_View();
}
else if (retval==2){
Dog.setImageResource(id);
Reset_View();
}
else if (retval==3){
Mouse.setImageResource(id);
Reset_View();
}
i++;
}
}
To try and delay the images showing at one at a time and to reset to it's default after showing for a few seconds I call Reset_View(); which is the following code:
CountDownTimer Reset_View = new CountDownTimer(1000 , 0010){
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
Centre.setImageResource(R.drawable.i1);
upperRight.setImageResource(R.drawable.i2);
lowerRight.setImageResource(R.drawable.i3);
lowerLeft.setImageResource(R.drawable.i4);
upperLeft.setImageResource(R.drawable.i5);
}
};
So how can I achieve what I want. I have been stuck on this idea for weeks.
This is a high level idea of what you could do.
Put all the showing and hiding in the countdowntimer. So basically you would need to handle the 'onTick' and hide or show the images when needed. Something like 'time > 0 and < 1000' hide all but the first image. 1000 to 2000, show only second image. 2000 to 3000, show only third image. On finish, hide all.
When you instantiate the timer after the for loop, if retval is 1 - then 1000 would be how long to run, retval = 2, then 2000, retval = 3, then 3000.
There is probably a better way to do it but this is the first thing that comes to my mind.
One problem might be that Reset_View(); is not a method. The line even states public CLASS Reset_View(); extends CountDownTimer. ( I don't know ho that can be a valid class name but whatever) Therefore, calling Reset_View(); will not actually do anything.
You need to change the name of the class to something else, I suggest ResetTimer. Then to reset the Views you must create an instance of ResetTimer and use its start() method like this:
new ResetTimer(1000, 1000).start();
Note: the first number in the constructor is the total time (in milliseconds) until the timers onFinish() is called. The second one it the time between the onTick()s. Since you don't use this method, the number you put in there doesn't matter.
I'm programming a simple game in java.
I've made a collision test with 30 FPS, where I had to get the size of the window.
Because I haven't had access to the GUI instance, I thought I'd make a shared instance, because this is pretty standard in Objective-C, where I come from.
class GUI extends JFrame {
private static GUI _sharedInstance;
public static GUI sharedInstance() {
if (_sharedInstance == null) {
_sharedInstance = new GUI();
}
return _sharedInstance;
}
}
But for some reason, it was really slow.
Then I replaced the shared instance with public static final instances for the size, and it works fast now, even with 60 FPS or higher.
Can anyone explain me why this happens?
EDIT
So instead of calling GUI.sharedInstance().getWidth(), I'm just calling GUI.windowSize.width.
I have used the public static final Dimension windowSize instead.
EDIT
Here's the collision detection.
So, instead of calling int width = GUI.kWindowWidth;,
I was calling int width = GUI.sharedInstance().getWidth(); before.
// Appears on other side
if (kAppearsOnOtherSide) {
int width = GUI.kWindowWidth;
int height = GUI.kWindowHeight;
// Slow
// int width = GUI.sharedInstance().getWidth();
// int width = GUI.sharedInstance().getHeight();
Point p = this.getSnakeHead().getLocation();
int headX = p.x;
int headY = p.y;
if (headX >= width) {
this.getSnakeHead().setLocation(new Point(headX - width, headY));
} else if (headX < 0) {
this.getSnakeHead().setLocation(new Point(headX + width, headY));
} else if (headY >= height) {
this.getSnakeHead().setLocation(new Point(headX, headY - height));
} else if (headY < 0) {
this.getSnakeHead().setLocation(new Point(headX, headY + height));
}
}
I know that this might not be the real answer to the question, but there could be a problem with a race condition.
I assume that you are trying to use the lazy/singleton pattern, because the construction of the GUI class is quite expensive and you need only one instance.
Now, what happens? If a thread runs into the if statement body, it creates a new GUI instance. Just before the next assignment, it gets paused by the scheduler.
Now another thread pops in, sees that _sharedInstance is still null and creates another GUI instance (and so on...).
Lets assume that there are only two threads.
The first thread runs to the end and the second one is continued, now you have two instances of the GUI class. Nobody says that the unassigned GUI instance gets destroyed or garbage collected.
That could explain tha 50 % performance loss compared to using finally and assigning the GUI instance directly to _sharedInstance.
See e.g. the Java examples at http://en.wikipedia.org/wiki/Singleton_pattern
Double checked locking, inner classes or an enum are the ways you can use.