I have a method named loadBalls(). In this method, I called another method named removeOldBalls().
In removeOldBalls(), I have a runnable to detach children on the scene.
Below are 2 methods :
public static void loadBalls() {
removeOldBalls();
for (int i = 0; i < MAX_BALL; i++) {
int x = MathUtils.random(0, CAMERA_WIDTH - BALL_SIZE);
int y = BALL_SIZE;
final Ball ball = new Ball(x, y, BALL_SIZE, BALL_SIZE, GraphicsManager.trBalloons[i]);
scene.registerTouchArea(ball);
balls.add(ball);
if (!balls.get(i).hasParent()) {
scene.attachChild(balls.get(i));
}
Log.e("test", "load");
}
}
public static void removeOldBalls() {
((BaseLiveWallpaperService) LWP.context).runOnUpdateThread(new Runnable() {
public void run() {
Log.e("test", "remove");
scene.detachChildren();
}
});
if (balls != null) {
int length = balls.size();
for (int i = 0; i < length; i++) {
fsw.destroyBody(balls.get(i).body);
}
balls.clear();
Log.e("test", "clear");
}
}
What I need is all children are removed before adding new ones. But when running above source code, the children are added first, then removed.
Please tell me how to wait for removing finish before adding.
I think look for the class android.os.Handler. Then you can create two threads: one to remove all the children and another to add the children. Then add those threads to the Handler like this:
handler.post(new Runnable(){
#Override
public void run() {
// Thread to remove children
}
});
handler.post(new Runnable(){
#Override
public void run() {
// Thread to add children
}
});
Once you add them one after another the Android SDK will execute them in the order they were added. So that will take care of your ordering issue.
Move the code which adds the children to another method, for example addBalls:
private void addBalls() {
for (int i = 0; i < MAX_BALL; i++) {
int x = MathUtils.random(0, CAMERA_WIDTH - BALL_SIZE);
int y = BALL_SIZE;
final Ball ball = new Ball(x, y, BALL_SIZE, BALL_SIZE, GraphicsManager.trBalloons[i]);
scene.registerTouchArea(ball);
balls.add(ball);
if (!balls.get(i).hasParent()) {
scene.attachChild(balls.get(i));
}
Log.e("test", "load");
}
}
And call this method fron the run method of the Runnable after you call scene.detachChildren:
public void run() {
Log.e("test", "remove");
scene.detachChildren();
addBalls();
}
Related
I want to redraw a customview multiple times within a for loop in a ClickListener. However, the view is only refreshed once on completion of the ClickListener code, not within the for loop.
Here is the relevant code snippet
vw = (TouchEventView)findViewById(R.id.TouchEventView);
clear = (Button)findViewById(R.id.button2);
clear.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
coords = TouchEventView.getFloats(TouchEventView.points);
if (coords.length < 4) {
Toast.makeText(MainActivity.this,"You must have at least one line",Toast.LENGTH_LONG).show();
}
else if ( coords.length < 6) {
SendData(length(coords[0],coords[1],coords[2],coords[3]));
SendData("s");
}
else {
for (int i = 0; i<coords.length-4; i=i+4) {
SendData(length(coords[i],coords[i+1],coords[i+2],coords[i+3]));
SendData(turn(coords[i],coords[i+1],coords[i+2],coords[i+3],coords[i+6],coords[i+7]));
}
int i = coords.length-4;
SendData(length(coords[i],coords[i+1],coords[i+2],coords[i+3]));
SendData("s");
// Now do the overlay
TouchEventView.retrace = true;
reords = new float[coords.length];
for (int j=0; j<coords.length-1; j=j+4) {
try {
Thread.sleep(1000);
}
catch (Exception e) {
}
// Log.e("pitrack","i : " + j);
TouchEventView.leg = j;
vw.postInvalidate();
}
}
}
});
and here is the onDraw method of the customview (TouchEventView)
#Override
protected void onDraw(Canvas canvas) {
if (retrace) {
canvas.drawLines(MainActivity.coords,paintRed);
canvas.drawLine(MainActivity.coords[leg],MainActivity.coords[leg+1],MainActivity.coords[leg+2],MainActivity.coords[leg+3],paintGreen);
}
else {
if (points.size() > 3) {
canvas.drawLines(getFloats(points),paintRed);
}
if (x > -1) {
canvas.drawLine(x, y, x1, y1, paintRed);
canvas.drawBitmap(finish,x1-96,y1-96,paintRed);
canvas.drawBitmap(start,startx-48,starty-48,paintRed);
}
}
}
Neither vw.invalidate() nor vw.postInvalidate() work other than at the end of the ClickListener process.
How can I force a redraw of the screen within the for loop?
The only solution I have found so far is to embed the customview.postInvalidate() as a runnable in a separate thread.
It is a shady workaround BUT you can force the view to invalidate, if you add another onclickListener off somekind. It worked for me when i came to showing a Progressbar while uploading something in the main thread (i had to do it that way). It is not pretty but it is working. Good Luck with that.
I have this RecyclerView that functions as a ticker, the auto scrolling works fine at first but after a period of time it becomes strange (back and forth) and the RecyclerView gets stuck at an item without smooth scrolling anymore, can anyone help me.
this is my layout manager:
LinearLayoutManager layoutManager = new LinearLayoutManager(HomeActivity.this, LinearLayoutManager.HORIZONTAL, false) {
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
LinearSmoothScroller smoothScroller = new LinearSmoothScroller(HomeActivity.this) {
private static final float SPEED = 5500f;// Change this value (default=25f)
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return SPEED / displayMetrics.densityDpi;
}
};
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
};
rvTicker.setLayoutManager(layoutManager);
this is my auto scrolling function:
public void autoScroll(){
speedScroll = 0;
handler = new Handler();
runnable = new Runnable() {
int count = 0;
#Override
public void run() {
if(count == tickerAdapter.getItemCount())
count = 0;
if(count < tickerAdapter.getItemCount()){
rvTicker.smoothScrollToPosition(++count);
handler.postDelayed(this,speedScroll);
}
}
};
handler.postDelayed(runnable,speedScroll);
}
SOLVED, I tweaked the autoscroll function:
public void autoScroll(){
speedScroll = 0;
handler = new Handler();
runnable = new Runnable() {
int count = 0;
#Override
public void run() {
if(count == tickerAdapter.getItemCount())
count = 0;
else {
if(count < tickerAdapter.getItemCount()){
rvTicker.smoothScrollToPosition(++count);
handler.postDelayed(this,speedScroll);
}else {
count = 0;
}
}
Log.wtf("tickerAdapter.getItemCount()", tickerAdapter.getItemCount()+"");
Log.wtf("count", count+"");
Log.wtf("++count", ++count+"");
Log.wtf("==============","=============");
}
};
handler.postDelayed(runnable,speedScroll);
}
I already spent hours searching and trying, but i cant get on the right path.
First my Code:
public class MyThreadLoc extends Thread{
Context context;
final ViewGroup view;
MyThreadLoc(Context context){
super();
this.context = context;
view = (ViewGroup) findViewById(R.id.mLayout);
}
int height;
#Override public void run() {
Looper.prepare();
int i = 0;
int y = 10;
while(running && i < 20){
i++;
if(y >= 200){
runOnUiThread(new Runnable() {
public void run() {
view.removeAllViews();
view.setBackgroundColor(Color.BLACK);
}
});
y=10;
}
try {
Thread.sleep( 500 );
Log.d("mystuff", "Sleep");
} catch ( InterruptedException e ) { e.printStackTrace(); }
final ViewGroup.LayoutParams lParam = new ViewGroup.LayoutParams(500,30); //MATCH_PARENT, 30);
while(y < 200 && running){
final float yb = y;
runOnUiThread(new Runnable() {
TextView tview;
public void run() {
Log.d("mystuff", "innerrun");
synchronized (view){
tview = new TextView(context);
tview.setText("Test");
tview.setY(yb);
view.addView(tview, lParam);
height = tview.getHeight();
view.updateViewLayout(tview, new RelativeLayout.LayoutParams(500,30));
Log.d("mystuff", Integer.toString(view.getChildCount()));
try {
Thread.sleep( 50 );
Log.d("mystuff", "Sleep");
} catch ( InterruptedException e ) { e.printStackTrace(); }
}
}
});
y = y + 100; //height +5;
}
The View doesn't appear first, but in the end 2 textviews with "Test" appear.
How can I update it, so that I see every single textview appearing?
Why didnt the somewhat-error that helped me to get this fixed, appear earlier so i didt need to ask this Question?
The error was: "Skipped 300 frames! The application may be doing too much work on its main thread"
Which brought me to: The application may be doing too much work on its main thread
So i removed most of the stuff from RunOnUiThread and now it works. Only 2 Textviews appeared because i had y < 200 set to low for more textviews to appear.
I wanted to display 9 images one after the other. I have included the 9 images as an array:
imageHolders = new ArrayList<ImageView>();
imageHolders.add((ImageView) view.findViewById(R.id.imgOne));
imageHolders.add((ImageView) view.findViewById(R.id.imgTwo));
imageHolders.add((ImageView) view.findViewById(R.id.imgThree));
imageHolders.add((ImageView) view.findViewById(R.id.imgFour));
imageHolders.add((ImageView) view.findViewById(R.id.imgFive));
imageHolders.add((ImageView) view.findViewById(R.id.imgSix));
imageHolders.add((ImageView) view.findViewById(R.id.imgSeven));
imageHolders.add((ImageView) view.findViewById(R.id.imgEight));
imageHolders.add((ImageView) view.findViewById(R.id.imgNine));
This is what I have tried:
public void handleMessage(Message msg) {
int currentImage = 0;
int nextImage = 0;
// Logic to change the images
for (final ImageView imageView : imageHolders) {
currentImage = Integer.parseInt(imageView.getTag().toString());
if (currentImage > 1) {
nextImage = currentImage - 1;
} else {
nextImage = 9;
}
imageView.setTag(""+nextImage);
new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
imageView.setVisibility(VISIBLE);
}
}.start();
}
super.handleMessage(msg);
}
}
There is a delay between the first and the second images. I am not able to introduce a delay between the rest. I have no clue about introducing the delay. Any suggestions would be appreciated.
you could just use AnimationDrawable which does this for you , and allows you to set a duration of time (in milliseconds) using android:duration attribute .
The AnimationDrawable is probably the best answer, but for another solution you can look at AsyncTask.
http://developer.android.com/reference/android/os/AsyncTask.html
Then, you can in the background just sleep for some set amount of time, then display the next image.
You may want an event though to handle when this task is done, and in the listener you call the next one.
If you want to make just a simple static animation (all images at the same position) you can use AnimationDrawable but you can't easly change it dynamically - like change speed or something.
I just wrote a simple class for this so I can set multiple animations for one ImageView and change speed.
public class ImageSequence extends ImageView {
ArrayList<Drawable> draws = new ArrayList<Drawable>();
ArrayList<Integer> bnds = new ArrayList<Integer>(); //bounds of sequences - index of first and last frame.
ArrayList<String> names = new ArrayList<String>(); //sequences names.
Timer timer = new Timer(true);
TimerTask task;
int p = -1; //current playback position.
int cS = -1; //current sequence.
public ImageSequence(Context context) {
super(context);
createTask();
}
public void addSequence(String name, int[] res){
names.add(name);
bnds.add(draws.size());
bnds.add(draws.size() + res.length - 1);
for (int i = 0; i < res.length; i++){
draws.add(getContext().getResources().getDrawable(res[i]));
}
}
public void play(String sequence, float speed){
cS = -1;
for(int i = 0; i < names.size(); i++){
if(names.get(i) == sequence){ cS = i; break;}
}
if(cS<0) return;
p = -1;
task.run();
task.cancel();
if(speed <= 0) return;
createTask();
timer.schedule(task, (long) (1000/speed), (long) (1000/speed));
}
public void stop(){
task.cancel();
}
public void cancelTimer(){
timer.cancel();
}
private void createTask() {
task = new TimerTask(){
public void run() {
p++;
mHandler.obtainMessage(1).sendToTarget();
}
};
}
public Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
int l = p;
if(l > bnds.get(cS*2+1) || l < bnds.get(cS*2)) l = bnds.get(cS*2);
p = l;
ImageSequence.this.setImageDrawable(draws.get(l));
}
};
}
From outside you can use it like this:
seq.addSequence("orange", new int[]{R.drawable.ic_oval_diode_orange, R.drawable.ic_oval_diode_off});
seq.addSequence("green", new int[]{R.drawable.ic_oval_diode_green, R.drawable.ic_oval_diode_off});
seq.addSequence("red", new int[]{R.drawable.ic_oval_diode_red, R.drawable.ic_oval_diode_off});
seq.play("red", 4);
I'm not really experienced in Android and Java but it works and it do the job for me. Hope it will help someone.
I need to achieve the following: animation starts, wait until it is finished and then continue with the code execution. The problem is how to "pause" the code execution while the main thread is running. OnAnimationEnd() methods are not suitable.
I can use postDelayed(Runnable r, long milliseconds) and to put all my code in the runnable, but I am not sure it is the best way to do this. Also tried with thread.sleep(), this.wait(), and another instance of thread with runnable threadnew.sleep(), but I don't see the desired behavior: it seems that wait and sleep stop the animation and the code execution, not just the code execution.
public boolean onLongClick (View v)
{
if((v==textView2)&&(androidturn == false)&&(animationongoing == false))
{
androidturn = true;
animationongoing = true;
L.startAnimation(inFromRightAnimation);
L.postDelayed(new Runnable() {
public void run() {
L.clearAnimation();
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.FILL_PARENT);
params.gravity = 0x50;
params.height =710;
L.setLayoutParams(params);
//L.layout(0,top,800,bottom);
animationongoing = false;
}
}, 500);
//here I need to stop the code execution for 500ms for animation to finish
imageButton1.setBackgroundResource(R.color.Red);
imageButton1.playSoundEffect(0);
try an AsyncTask
here's an example it won't block the ui thread
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
/*setProgressPercent(progress[0]);*/
}
protected void onPostExecute(Long result) {
/* call continute method here */
}
}
sr: http://developer.android.com/reference/android/os/AsyncTask.html
Separate the part to run after into its own method, then call it immediately or in the callback as appropriate.
public boolean onLongClick (View v)
{
if((v==textView2)&&(androidturn == false)&&(animationongoing == false))
{
androidturn = true;
animationongoing = true;
inFromRightAnimation.setAnimationListener(new Animation.AnimationListener()
{
// Other listeners omitted.
public void onAnimationEnd(Animation anim) {
L.clearAnimation();
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.FILL_PARENT);
params.gravity = 0x50;
params.height =710;
L.setLayoutParams(params);
//L.layout(0,top,800,bottom);
animationongoing = false;
styleImageButton();
}
});
L.startAnimation(inFromRightAnimation);
}
else
{
styleImageButton();
}
}
private void styleImageButton()
{
imageButton1.setBackgroundResource(R.color.Red);
imageButton1.playSoundEffect(0);
}
In async code, you want to avoid forcing code to wait.
EDIT: I fixed my code to use onAnimationEnd.