I have an Android app that needs to display images and videos in a loop, it has no problem with playing the videos, but when it gets to the images the screen goes blank and nothing happens. the program is still running just not displaying.
I'm using SurfaceView.setBackground() to draw the image because swapping between an ImageView and the SurfaceView that the videos are played on has caused problems before.
I was having a similar issue when displaying the videos and I solved it by removing the loop I had waiting for the video to be prepared so ideally I would like to remove the loop I have waiting for a timer to elapse.
I have a function to display the new media when the old one is finished and it also prepares the next one for when the current one is finished. If the media is a video this is called from the onComplete function which works fine. But if it is an image I have a wait loop.
What I want to do is have something like the MediaPlayer.onComplete() function to be called when the image has been displayed for the desired amount of time. Does anything like this exist?
I have since changed this to use handlers because of some other error checking I needed to do. However the other way does work
mHandler.postdelayed(run, delay);
Runnable run = new Runnable(){
public void run()
{
//run function
}
};
I figured it out. I made a new thread that ran a timer and calls a function in the main activity that updates the screen. The call to the function that updates the screen is called using runOnUiThread() so that it has permission to change the screen.
public class ImageTimer implements Runnable{
private long dur, cur,start;
private boolean needed, run;
private Activity mAct;
ImageTimer(boolean running, long duration, Activity act)
{
run = running;
dur = duration;
needed = false;
mAct = act;
}
#Override
public void run()
{
while(run)
{
if(needed)
{
start = System.currentTimeMillis();
cur = System.currentTimeMillis() - start;
while(cur < dur)
{
cur = System.currentTimeMillis() - start;
}
needed = false ;
mAct.runOnUiThread(new Runnable()
{
public void run()
{
MainActivity.ImageDone();
}
});
}
}
}
Related
I defined a Runnable which starts after a button clicked,
it changes image of a ImageView every 1 second.
There is an other button in my view that when user click on that, again I start that Runnable but this time it changes image of ImageView every 2 seconds and so on.
My question is: when I click on second button, now do I have to individual thread running or it just stop first instance of Runnable and start the other instance?
Note: I read some topics about threads and Runnable in android but still the different is not clear for me.
Also reading this question and it's answers head me hear to ask my own question.
Java - Running a thread twice
Sorry for bad English.
Runnable part of my code:
private final Runnable mRunnable = new Runnable() {
public void run() {
if (mIsFlashOn) {
if (mSwap) {
mImageViewBeam.setVisibility(View.VISIBLE);
mSwap = false;
mHander.postDelayed(mRunnable, 10000 / ((mStrobeCounter * 5) + 10));
} else {
mImageViewBeam.setVisibility(View.GONE);
mSwap = true;
mHander.postDelayed(mRunnable, 10000 / ((mStrobeCounter * 5) + 10));
}
}
}
};
I think you need to use mHandler.removeCallbacks(mRunnable); this line to remove first runnable , and than start another
So from your code what have I understood is, you're creating a thread inside a while loop which is updating the ImageView over the time. If I've understood correctly then its really a bad practice to do so. I might be wrong. Please post your updating code in that case. How you're updating the ImageView?
If I'm right, try considering CountDownTimer which will serve your purpose I hope.
CountDownTimer mCountDownTimer = new CountDownTimer(howLongYouWantItToRunInMilis, intervalInMilis) {
public void onTick(long remainingMilis) {
// Update your ImageView here
if (mSwap) {
mImageViewBeam.setVisibility(View.VISIBLE);
mSwap = false;
} else {
mImageViewBeam.setVisibility(View.GONE);
mSwap = true;
}
}
public void onFinish() {
// Start the timer again from the code.
}
}.start();
Set the intervalInMilis when the button is clicked. Then mCountDownTimer.cancel() to cancel the timer and mCountDownTimer.start() to start it again immediately.
I've got some problem with sendKeyDownUpSync. I want to use it in my widget to control inbuilt music player. It works almost correctly. Almost because when i call function:
public void previousTruck()
{
final Instrumentation inst = new Instrumentation();
new Thread(new Runnable() {
public void run() {
new Instrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
}).start();
}
It start changing music from my playlist but lots of time, why?
I want to make only one "step" to next song from play list.
Somewhere in the OnCreate
myThread = new Thread()
{
public void run()
{
Instrumentation m_Instrumentation = new Instrumentation();
m_Instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
}
};
Somewhere in your previousTruck
myThread.start();
P.S. Be attentive!! Creating Thread object without the run() invoking causes the memory leak - see. It happens during changing of screen orientation if you create a thread object inside the OnCreate and there is not the run() invoking till the next changing of screen orientation. That is why the best approach is to create Thread object immediately before it's start() invoking.
I can't understand the implementation of a while loop in android.
Whenever I implement a while loop inside the onCreate() bundle, (code shown below)
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView=(TextView)findViewById(R.id.TextView);
while (testByte == 0)
updateAuto();
}
nothing boots up, and the program enters a "hanging" state after a while and I can't understand why. Testbyte is as follows:
byte testByte == 0;
and updateAuto() is supposed to update the code per 1 second and display inside the textView portion. I've been using setText inside updateAuto() as shown below and everything works fine, but once i implement the while loop all i see is a black screen and then an option to force close after a few seconds due to it "not responding".
TextView.setText(updateWords);
I've changed it to a button format (meaning i have to click on the button to update itself for now), but i want it to update itself instead of manually clicking it.
Am i implementing the while loop in a wrong way?
I've also tried calling the while loop in a seperate function but it still gives me the black screen of nothingness.
I've been reading something about a Handler service... what does it do? Can the Handler service update my TextView in a safer or memory efficient way?
Many thanks if anyone would give some pointers on what i should do on this.
Brace yourself. And try to follow closely, this will be invaluable as a dev.
While loops really should only be implemented in a separate Thread. A separate thread is like a second process running in your app. The reason why it force closed is because you ran the loop in the UI thread, making the UI unable to do anything except for going through that loop. You have to place that loop into the second Thread so the UI Thread can be free to run. When threading, you can't update the GUI unless you are in the UI Thread. Here is how it would be done in this case.
First, you create a Runnable, which will contain the code that loops in it's run method. In that Runnable, you will have to make a second Runnable that posts to the UI thread. For example:
TextView myTextView = (TextView) findViewById(R.id.myTextView); //grab your tv
Runnable myRunnable = new Runnable() {
#Override
public void run() {
while (testByte == 0) {
Thread.sleep(1000); // Waits for 1 second (1000 milliseconds)
String updateWords = updateAuto(); // make updateAuto() return a string
myTextView.post(new Runnable() {
#Override
public void run() {
myTextView.setText(updateWords);
});
}
}
};
Next just create your thread using the Runnable and start it.
Thread myThread = new Thread(myRunnable);
myThread.start();
You should now see your app looping with no force closes.
You can create a new Thread for a while loop.
This code will create a new thread to wait for a boolean value to change its state.
private volatile boolean isClickable = false;
new Thread() {
#Override
public void run() {
super.run();
while (!isClickable) {
// boolean is still false, thread is still running
}
// do your stuff here after the loop is finished
}
}.start();
Im doing a little app, its a memory game, you choose one card, it turns up, you choose the second card, it turns up, if they are the same they are out of the game, if they dont match, they are turned down again.
I have
public class PlayActivity extends Activity implements OnClickListener.
The flip events are trigged by click handlers, declared at public void onCreate(Bundle savedInstanceState) they work fine.
When the first card is selected, it calls my method Action, this sets the image from default (the card back) to the 'real' image (the card front). Fine so far.
My problem is the second card: when its selected, it calls method Action, where it should set the front image (lets call it 'middle action'), then a litle pause (a while loop doing nothing until x milliseconds), and then it checks what to do (if they match or not) and turn them down or take the out of the game. You can see where is the problem: the screen only displays the result after x milliseconds (the 'middle action' is not being draw).
Since I have done some little games with XNA, I know the loop Update-Draw, so I know here im updating the same thing twice so always the last one is drawn. But here, the only updating I can have is when click events are trigged, I need a periodic, constant update.
Help?
You can probably use a TimerTask in order to handle that. You can implement it like the following.
This probably isn't the most robust way to do it, but it is an idea. If I figure out a better way to do it in a short time I'll edit my post. :)
Also I would like to add that if you want to make a game that uses an update / draw loop you may need to use a SurfaceView to draw your game. Look at the example here http://developer.android.com/resources/samples/JetBoy/index.html
public class TestGameActivity extends Activity {
/* UIHandler prevents exceptions from
performing UI logic on a non-UI thread */
private static final int MESSAGE_HIDE_CARD = 0;
private class UIHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_HIDE_CARD:
ImageView cardView = (ImageView) msg.obj;
cardView.setImageResource(R.drawable.faceDownCard);
break;
}
}
}
private UIHandler handler = new UIHandler();
// Handle my click. V is the card view
public void onClick(View v) {
final int viewID = v.getId();
// Create a hide task
TimerTask hideTask = new TimerTask() {
#Override
public void run() {
// Construct a message so you won't get an exception
Message msg = new Message();
msg.what = MESSAGE_HIDE_CARD;
msg.obj = findViewById(viewID);
handler.sendMessage(msg);
}
};
// Schedule the task for 2 seconds
new Timer().schedule(hideTask, 2000);
}
}
I tried plugging a SeekBar into my video app, but it doesn't seem to ever reach the end of the bar. Here's the code:
videoSeekBar = (SeekBar) activity.findViewById(R.id.videoPlayerSeek);
videoDuration = player.getDuration();
videoSeekBar.setMax(videoDuration);
videoSeekBar.setProgress(0);
// Start lengthy operation in a background thread
new Thread(new Runnable() {
public void run() {
while (videoPlayProgress < videoDuration) {
videoPlayProgress = player.getCurrentPosition();
// Update the progress bar
handler.post(new Runnable() {
public void run() {
videoSeekBar.setProgress(videoPlayProgress);
}
});
}
}
}).start();
Then, I have an OnCompleteListener attached to the MediaPlayer. When it is called,
player.getCurrentPosition() returns 6209
player.getDuration() returns 6592
Which can't be right. At this point, the slider status indicator isn't quite at the end of the slider bar, but there's a slight gap. The shorter the video's length, the bigger the gap.
First, consider <= instead of <.
More importantly, you do not need or want a busy-loop background thread for this. Go with something like:
Runnable r=new Runnable() {
public void run() {
videoSeekBar.setProgress(player.getCurrentPosition());
if (player.getCurrentPosition()<player.getDuration()) {
videoSeekBar.postDelayed(r, 33);
}
}
};
and somewhere call run() on r, when your video starts up. This will update the SeekBar about 30 times per second.
Your current implementation is a foreground busy loop, posting thousands of messages onto the main application thread's queue, which will make your video playback performance worse and waste battery for no particular advantage.
This still might not get all the way to the end -- it's possible that the video will reach the end between the setProgress() call and the if test. The true test of it being at the end is the OnCompletionListener, so just position the SeekBar at the end at that point.