i have imageView
<ImageView
android:id="#+id/loading"
android:layout_width="40dp"
android:layout_height="40dp"
android:scaleType="centerCrop"
android:layout_gravity="center_horizontal"
android:src="#drawable/spinner"/>
and image is
i want create an animation which change position of image inside imageView
i tried this
android:scrollX="-80dp"
this in xml and static i want animation
You can do it by creating a thread and a handler where the thread sleeps for a certain amount of time and informs handler by sending message when it wakes up and handler will update the image in image view.
Create 4 Fields like below :
private ImageView mImageView;
private Handler mImageChangingHandler;
private int mCurrentImageIndex = 0;
private BackgroundThread mImageUpdateThread;
In onCreate() get the ImageView, spilt your bitmaps and add it to a list and create a handler which updates imageview. Here you should know the number of individual bitmaps which is in main Bitmap. Like :
mImageView = (ImageView) findViewById(R.id.img);
Bitmap mainBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.anim);
//number of individual bitmaps, which you should know.
final int numberOfImages = 21;
//individual bitmap width
int bitmapWidth = mainBitmap.getWidth() / numberOfImages;
//individual bitmap height
int bitmapHeight = mainBitmap.getHeight();
//list which holds individual bitmaps.
final List<Bitmap> animBitmaps = new ArrayList<>(numberOfImages);
//split your bitmap in to individual bitmaps
for (int index = 0; index < numberOfImages; index++) {
animBitmaps.add(Bitmap.createBitmap(mainBitmap, index * bitmapWidth, 0, bitmapWidth, bitmapHeight));
}
//set 1st bitmap to imageView.
mImageView.setImageBitmap(animBitmaps.get(mCurrentImageIndex));
mImageChangingHandler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
//increament current bitmap index
mCurrentImageIndex++;
//if current index is greater than the number of images, reset it to 0
if (mCurrentImageIndex > numberOfImages - 1) {
mCurrentImageIndex = 0;
}
mImageView.setImageBitmap(animBitmaps.get(mCurrentImageIndex));
return true;
}
});
//Create the background thread by passing the handler and start.
mImageUpdateThread = new BackgroundThread(mImageChangingHandler);
mImageUpdateThread.setRunning(true);
mImageUpdateThread.start();
And This will be your BackgroundThread.class :
public static class BackgroundThread extends Thread {
private Handler mHandler;
private boolean mRunning;
public BackgroundThread(Handler handler) {
mHandler = handler;
}
public void setRunning(boolean running) {
mRunning = running;
}
#Override
public void run() {
super.run();
while (mRunning) {
try {
//this sleeps for 100 milliseconds
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//send message to handler after sleep
mHandler.sendEmptyMessage(0);
}
}
}
}
Finally in onDestroy() stop the thread. Like :
mImageUpdateThread.setRunning(false);
boolean stopThread = true;
while (stopThread) {
try {
mImageUpdateThread.join();
//thread already stopped
stopThread = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mImageUpdateThread = null;
Note : If you want to increase the update speed, reduce the sleep time in thread.
Related
I am using WallpaperService to set the live wallpaper on homescreen. I am able to set 10 pics from resources and rotate them,
based on static frequency using thread. I want user to give the option of selecting multiple frequency. I tried to pass the thread sleep duration with user selected frequency. But the thread which is running is neither stopping or updating the values.
Its updating wallpaper with the previous selected frequency. Im stuck with this app from 3 weeks at various levels. I have tried wallpaper manager and setting bitmap with services, alarm manager but all are stopping to set the wallpaper after certain period of time. So finally using Wallpaper service. Help to overcome from this issue.
class WallpaperEngine extends Engine {
//frequency selected by user to update the wallpaper
private final int Wallpaper_DURATION = utils.getFrequency;
private int[] mImagesArray;
private int mImagesArrayIndex = 0;
private Thread mDrawWallpaper;
public WallpaperEngine() {
customWallpaperHelper = new CustomWallpaperHelper(getApplicationContext(), getResources());
mImagesArray = new int[] {R.drawable.one,R.drawable.two,R.drawable.three,R.drawable.four,R.drawable.five};
mDrawWallpaper = new Thread(new Runnable() {
#Override
public void run() {
try {
while (true) {
drawFrame();
incrementCounter();
Thread.sleep(Wallpaper_DURATION);
}
} catch (Exception e) {
//
}
}
});
mDrawWallpaper.start();
}
private void incrementCounter() {
mImagesArrayIndex++;
if (mImagesArrayIndex >= mImagesArray.length) {
mImagesArrayIndex = 0;
}
}
private void drawFrame() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
if (canvas != null) {
drawImage(canvas);
}
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
private void drawImage(Canvas canvas)
{
Bitmap image = BitmapFactory.decodeResource(getResources(),
mImagesArray[mImagesArrayIndex]);
Bitmap b=Bitmap.createScaledBitmap(image, canvas.getWidth(), canvas.getHeight(), true);
canvas.drawBitmap(b, 0,0, null);
}
I am a beginner in Android app dev. Recently I am trying to make a face detection app using FaceDetector.
In the code below is my main activity class. I have a Runnable to loop through a set of images, convert to bitmaps and send them to FaceOverlayView to find and draw faces. The loop can go through all 4 items.
However, as I tried to make it loop all over again by setting index to 0 after the last item, the app crashes. I observed the behavior that the app will crash trying to reload an image loaded before. Would you please give me any insight on this? Many thanks in advance.
public class MainActivity extends AppCompatActivity {
private FaceOverlayView mFaceOverlayView;
Handler handler;
Thread thread;
ArrayList<Integer> imgID = new ArrayList<Integer>(Arrays.asList(R.raw.face1, R.raw.face2, R.raw.face3, R.raw.face4));
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFaceOverlayView = (FaceOverlayView) findViewById(R.id.face_overlay);
thread = new Thread(new myThread());
thread.start();
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.arg1 == -1) {
//thread.interrupt();
}
Bitmap bitmap = (Bitmap) msg.obj;
mFaceOverlayView.setBitmap(bitmap);
}
};
}
class myThread implements Runnable {
#Override
public void run() {
int index = 0;
while (index < imgID.size()) {
InputStream stream = getResources().openRawResource(imgID.get(index));
Bitmap bitmap = BitmapFactory.decodeStream(stream);
Message msg = Message.obtain();
msg.obj = bitmap;
handler.sendMessage(msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
index++;
if (index >= imgID.size()) {
index = 0;
}
bitmap.recycle();
bitmap = null;
}
}
}
}
I use an AsyncTask class for execute a task and show an ImageView.
But I execute this task every 10 seconds, for this I call the same task in :
onPostExecute() method.
It's work but the imageView refresh after 10 seconds, why ?
This is my code :
#Override
protected void onPostExecute(Void result) {
ProgressBar progress = (ProgressBar) rootView.findViewById(R.id.progress);
progress.setVisibility(View.GONE);
ImageView imageView = (ImageView) rootView.findViewById(R.id.myView);
imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
SVG svg;
InputStream is = null;
try {
is = new FileInputStream(mySVG);
svg = SVG.getFromInputStream(is);
Drawable drawable = new PictureDrawable(svg.renderToPicture());
imageView.setImageDrawable(drawable);
} catch (SVGParseException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
imageView.refreshDrawableState();
long start = System.currentTimeMillis();
while ((System.currentTimeMillis() - start) < 10000) {
}
AsyncTask<Object, Integer, Void> t = new Task(rootView).execute();
}
This code refresh the imageView after 10 seconds, but I would refreshed immediately, wait 10 seconds and execute another Task...
Wow, you're using an AsyncTask and then "eat CPU" in the onPostExecute()
while ((System.currentTimeMillis() - start) < 10000) {
}
Don't do this.
Use a Handler / Runnable combination.
Here's an example:
In your Activity you do:
private Handler timerHandler;
private Runnable timerRunnable;
// ...
#Override
public void onCreate() {
super.onCreate();
timerHandler = new Handler();
timerRunnable = new Runnable() {
#Override
public void run() {
// do your refresh here
timerHandler.postDelayed(timerRunnable, 10000);
}
};
timerHandler.post(timerRunnable);
}
I have to manipulate pixels of a bitmap every one second, during another operation, and show the result in ImageView. This is a method that manipulates bitmap and updates ImageView:
private void overlay(Bitmap bitmap) {
int j = 70;
while (flag) {
//here I manipulate some pixels of bitmap that corresponds to "j"
//and save result in "tempBmp":
...
//update imageView:
iv1.setImageBitmap(tempBmp);
iv1.postInvalidate();
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// }
//update "j":
j = (j+1)%src.rows();
}
}
Above method is called from UI thread (onclick event of button) in this way:
runOnUiThread(new Runnable() {
public void run() {
overlay(bmp);
}
});
When App is running, there is no problem, App crash or ANR, but the ImageView (iv1) does not update. I debug the code and bitmap's pixels are manipulating. Also I uncomment try/catch block, but the result was the same.
It is strange: when I comment start and end of while block, bitmap manipulate correctly (one time and for j = 70) and the ImageView updates as expected!
Update question:
With respect to comments and answers of eshayne and Onik I changed pixel manipulation in overlay method to a simple operation and check the result, but result was the same. Real overlay method use openCV but here I change color of pixels, so you can see result without using openCV:
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
new Thread(new Runnable() {
#Override
public void run() {
overlay(bmp);
}
}).run();
}
});
overlay method,simplified:
private void overlay(Bitmap bitmap){
int j = 0;
tempBmp = Bitmap.createBitmap(bitmap);
while (j < bitmap.getHeight()) {
for (int i = 0; i < bitmap.getWidth(); i++) {
tempBmp.setPixel(i, j, 0);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// post the changes to Ui thread
iv1.post(new Runnable() {
#Override
public void run() {
iv1.setImageBitmap(tempBmp);
}
});
j = (j + 1);
}
}
How can I update ImageView, every second with while? Did I do any thing wrong?
Try moving your loop outside of the UI thread, then just run the setImageBitmap call within the UI thread. Something like:
// from non-UI thread:
while (flag) {
// perform image manipulation
runOnUiThread(new Runnable() {
#Override
public void run() {
iv1.setImageBitmap(tempBmp);
}
});
}
What I'm trying to create is a simple progress bar, that would load for ~10 sec.
So what I want is a for loop like this:
for(int i = 1; i <= 100; i++) {
progressDialog.setProgress(i);
//100ms delay
}
Thanks
You can use Async Task for the purpose
in preExecute() method initialize loop index to 0;
in background process sleep thread for 10 seconds, and then call sendUpdate method to send progress
in postExecute update progress bar to progress get in parameter.
The following code may be helpful for you.
public void startProgress(View view) {
// Do something long
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
progressDialog.setProgress(value);
}
});
}
}
};
new Thread(runnable).start();
}
A shorter solution without explicitly creating a new Thread would look like this:
final Handler handler = new Handler(Looper.getMainLooper());
final int sleepMs = 100;
for (int i = 1; i <= 100; ++i) {
handler.postDelayed(() -> progressDialog.setProgress(value), i * sleepMs);
}