I want to create a small android app that would show the system time in periodic intervals after clicking on a button ( i.e. setting the activity up )...The code for button creation and setting the periodic activity via Intent goes like this :
package com.example.timeupdate;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
Button button;
TextView show;
#Override
protected void onCreate(Bundle I_Love_Biriyani) {
super.onCreate(I_Love_Biriyani);
setContentView(R.layout.activity_main);
button = (Button) findViewById (R.id.pressButton);
show = (TextView) findViewById (R.id.Show);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent openTimeUpdater = new Intent("com.example.timeupdate.TIMEUPDATER");
startActivity(openTimeUpdater);
}
});
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
finish();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
And here is the code for repeating the timer( for say 5 seconds ) where I used TimerTask class to perform the job :
package com.example.timeupdate;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class TimeUpdater extends Activity {
TextView Show;
TimerTask timer= new TimerTask(){
#Override
public void run() {
// TODO Auto-generated method stub
Date d = new Date();
Show.setText(""+d);
}
};
#Override
protected void onCreate(Bundle hotovaga) throws IllegalStateException {
// TODO Auto-generated method stub
super.onCreate(hotovaga);
setContentView(R.layout.new_update);
Show = (TextView) findViewById (R.id.time);
Timer t = new Timer();
t.scheduleAtFixedRate(timer , 0 , 5000);
}
}
After clicking on the button the time is shown only once then application is getting stopped showing a dialog-message. Need explanations to do this job in the same fashion.
You are trying to access an UI element inside non-UI thread.
Show.setText(""+d);
Instead, wrap it up in runOnUiThread interface to get proper output.
Use below code for your TimeUpdater class
public class TimeUpdater extends Activity {
TextView Show = null;
Calendar c;
int seconds;
int minutes;
int hours;
TimerTask timer= new TimerTask(){
#Override
public void run() {
c = Calendar.getInstance();
seconds = c.get(Calendar.SECOND);
minutes = c.get(Calendar.MINUTE);
hours = c.get(Calendar.HOUR);
runOnUiThread(new Runnable() {
#Override
public void run() {
Show.setText(hours + ":" + minutes + ":" + seconds);
}
});
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.new_update);
Show = (TextView) findViewById (R.id.time);
Timer t = new Timer();
t.scheduleAtFixedRate(timer , 0 , 5000);
}
}
Using an actual Timer (java.util.Timer) in conjunction with runOnUiThread() is one way to solve this issue, and below is an example of how to implement it.
public class myActivity extends Activity {
private Timer myTimer;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
myTimer = new Timer();
myTimer.schedule(new TimerTask() {
#Override
public void run() {
TimerMethod();
}
}, 0, 1000);
}
private void TimerMethod()
{
//This method is called directly by the timer
//and runs in the same thread as the timer.
//We call the method that will work with the UI
//through the runOnUiThread method.
this.runOnUiThread(Timer_Tick);
}
private Runnable Timer_Tick = new Runnable() {
public void run() {
//This method runs in the same thread as the UI.
// Set your textView data here.
//Do something to the UI thread here
}
};
}
use PeriodicTask from Play-Service, it is the newest tool from Google to schedule a job background.
Related
I have a small application Image Slider. There is a scrolling timer for the picture. The timer does not stop if the user is active and scans the images manually. How to pause the timer for the user and resume it in the event that the activity has stopped. Help me please. I'm just starting to study iandroid studio/
MainActivity.java
package com.androidtutorialpoint.androidimageslider;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import me.relex.circleindicator.CircleIndicator;
public class MainActivity extends AppCompatActivity {
private static ViewPager mPager;
private static int currentPage = 0;
private static final Integer[] XMEN= {R.drawable.beast,R.drawable.charles,R.drawable.magneto,R.drawable.mystique,R.drawable.wolverine};
private ArrayList<Integer> XMENArray = new ArrayList<Integer>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
for(int i=0;i<XMEN.length;i++)
XMENArray.add(XMEN[i]);
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(new MyAdapter(MainActivity.this,XMENArray));
CircleIndicator indicator = (CircleIndicator) findViewById(R.id.indicator);
indicator.setViewPager(mPager);
// Auto start of viewpager
final Handler handler = new Handler();
final Runnable Update = new Runnable() {
public void run() {
if (currentPage == XMEN.length) {
currentPage = 0;
}
mPager.setCurrentItem(currentPage++, true);
}
};
Timer swipeTimer = new Timer();
swipeTimer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(Update);
}
}, 2500, 3000);
}
}
You can pause the handler in the activity onPause lifecycle callback. There's an example located here: Android, pausing and resuming handler callbacks
You can then resume the timer in the activity onResume() lifecycle callback.
I am trying to create a simple Android stopwatch application. I was having trouble with the application freezing every time I would hit the start button. I learned from reading various things online that the reason it hangs is that I ran a while loop in the UI thread and in order for the application not to crash, that while loop had to be somewhere different. A post on the XDA forums suggested that someone encountering this problem should use an AsyncTask to accomplish this. I am having trouble understanding exactly how to use AsyncTask to do this.
TL;DR: I am trying to count time and then have it update a textview with the corresponding time
Original code with while loop in UI thread
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity
{
Button start, stop, reset;
TextView time;
boolean timeStopped = false;
long timeInNanoSeconds, startTimeInNanoSeconds;
double timer;
public double getTimeInSeconds()
{
timeInNanoSeconds = System.nanoTime() - startTimeInNanoSeconds;
double timeSeconds = (double) timeInNanoSeconds / 1000000000.0;
double roundOff = Math.round(timeSeconds * 100.0) / 100.0;
return roundOff;
}
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.startButton);
stop = (Button) findViewById(R.id.stopButton);
reset = (Button) findViewById(R.id.resetButton);
time = (TextView) findViewById(R.id.timeField);
start.setOnClickListener(new View.OnClickListener()
{
public void onClick(View arg0)
{
startTimeInNanoSeconds = System.nanoTime();
while(timeStopped == false)
{
double timer = getTimeInSeconds();
String stringTimer = Double.toString(timer);
CharSequence sequenceTimer = stringTimer;
time.setText(sequenceTimer);
}
}
});
stop.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
}
});
reset.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
time.setText("");
}
});
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
EDIT: Working version using Handler
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
Button start, stop, reset;
TextView time;
Handler m_handler;
Runnable m_handlerTask;
int timeleft = 0;
boolean timeStopped;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.buttonStart);
stop = (Button) findViewById(R.id.buttonStop);
reset = (Button) findViewById(R.id.buttonReset);
time = (TextView) findViewById(R.id.textTime);
start.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
timeStopped = false;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
public void run() {
if(timeStopped == false){
if(timeleft > -1) {
Log.i("timeleft","" + timeleft);
time.setText(String.valueOf(timeleft));
timeleft++;
}
else{
m_handler.removeCallbacks(m_handlerTask);
}
}
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
}
});
stop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
timeStopped = true;
m_handler.removeCallbacks(m_handlerTask);
}
});
reset.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
timeStopped = true;
m_handler.removeCallbacks(m_handlerTask);
timeleft = 0;
time.setText(String.valueOf(timeleft));
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
doInbackground is invoked on the background thread. you cannot update ui from a background
time.setText(sequenceTimer);
// should be in a ui thread.
Use runOnUithread or setText in onPostExecute.
You can use a Handler , a timer task or a CountDowntimer depending on your requirement.
Android Thread for a timer
Edit:
Using Handler
public class MainActivity extends Activity
{
Button start;
TextView time;
Handler m_handler;
Runnable m_handlerTask ;
int timeleft=100;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.button1);
time = (TextView)findViewById(R.id.textView1);
start.setOnClickListener(new View.OnClickListener()
{
public void onClick(View arg0)
{
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
if(timeleft>=0)
{
// do stuff
Log.i("timeleft",""+timeleft);
time.setText(String.valueOf(timeleft));
timeleft--;
}
else
{
m_handler.removeCallbacks(m_handlerTask); // cancel run
}
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
}
});
}
}
In my opinion AsyncTask is not fit for you, as this in my mind is a single shot action.
I would suggest something like this:
private ScheduledExecutorService exec;
private void startExec() {
shutDownExec();
exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
// this starts immediately and is run once every minute
double timer = getTimeInSeconds();
String stringTimer = Double.toString(timer);
CharSequence sequenceTimer = stringTimer;
runOnUiThread(new UpdateUI(R.id.yourtime_textview, sequenceTimer));
}
}, 0, 1, TimeUnit.MINUTES); // adjust how often run() is executed here
}
private void shutDownExec() {
if (exec != null && !exec.isTerminated()) {
exec.shutdown();
}
}
private class UpdateUI implements Runnable {
private String mText;
private TextView mTv;
public UpdateUI(int textviewid, String text) {
this.mTv = (TextView) findViewById(textviewid);
this.mText = text;
}
#Override
public void run() {
mTv.setText(mText);
}
}
I had to do a similar task lately I used created a separate thread with the following code. It lets you update at set time intervals which I think would be suited to your task.
Hope it helps.
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
public class AutomationTreadClass {
Activity refToUIActivity;
//Declare the timer
Timer t = new Timer();
//pass UI activity so you can call update on it
AutomationTreadClass( Activity callingActivity ){
refToUIActivity = callingActivity;
startTimerTread();
}
private void startTimerTread(){
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//do any updates to the time you need to do here
updateLevelMeter();
}
},
//Start Time of thread
0,
//interval of updates
30);
}
private void updateLevelMeter() {
refToUIActivity.runOnUiThread(new Runnable() {
public void run() {
//access what ever UI comment you need to here. like giving you textview a value.
}
});
}
}
Expected result
A button can act in a way like a toggle, such that,
(1) first time clicking on it, the button moves rightward
(2) second time clicking on it, the button moves leftward
(3) third time clicking on it, the button moves rightward
and so on....
Problem
The flag variable flagToggleButton cannot be used in button's OnClickListener event listener callback function.
Main.java
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
public class Main extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button b = (Button) findViewById(R.id.button1);
boolean flagToggleButton = false;
b.setOnClickListener(new OnClickListener () {
#Override
public void onClick(View arg0) {
if (flagToggleButton == false) {
Animation anim = AnimationUtils.loadAnimation(Main.this,
R.anim.animation_move_right);
b.startAnimation(anim);
flagToggleButton = true;
}
else {
Animation anim = AnimationUtils.loadAnimation(Main.this,
R.anim.animation_move_left);
b.startAnimation(anim);
flagToggleButton = false;
}
}
});
}
}
Make it a member variable of your class. In other words, define it outside onCreate()
public class Main extends Activity {
boolean flagToggleButton = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
// rest of your code
Put globally
boolean flagToggleButton = false;
b.setOnClickListener(new OnClickListener () {
#Override
public void onClick(View arg0) {
if (!(flagToggleButton)) {
// do stuff..
flagToggleButton = true;
}
else {
// do stuff..
flagToggleButton = false;
}
}
});
so i have this code to stream an mp3, now i was wondering how can i make the music stop when someone exits the app with the back button/home button. Even if i exit the app and close it the music is still playing in the background and i have no way to make it stop.
package com.hrupin.streamingmedia;
import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.SeekBar;
import com.hrupin.media.R;
public class StreamingMp3Player extends Activity implements OnClickListener, OnTouchListener, OnCompletionListener, OnBufferingUpdateListener{
private ImageButton buttonPlayPause;
private SeekBar seekBarProgress;
public EditText editTextSongURL;
private MediaPlayer mediaPlayer;
private int mediaFileLengthInMilliseconds; // this value contains the song duration in milliseconds. Look at getDuration() method in MediaPlayer class
private final Handler handler = new Handler();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initView();
}
/** This method initialise all the views in project*/
private void initView() {
buttonPlayPause = (ImageButton)findViewById(R.id.ButtonTestPlayPause);
buttonPlayPause.setOnClickListener(this);
seekBarProgress = (SeekBar)findViewById(R.id.SeekBarTestPlay);
seekBarProgress.setMax(99); // It means 100% .0-99
seekBarProgress.setOnTouchListener(this);
//editTextSongURL = (EditText)findViewById(R.id.EditTextSongURL);
//editTextSongURL.setText(R.string.testsong_20_sec);
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnCompletionListener(this);
}
/** Method which updates the SeekBar primary progress by current song playing position*/
private void primarySeekBarProgressUpdater() {
seekBarProgress.setProgress((int)(((float)mediaPlayer.getCurrentPosition()/mediaFileLengthInMilliseconds)*100)); // This math construction give a percentage of "was playing"/"song length"
if (mediaPlayer.isPlaying()) {
Runnable notification = new Runnable() {
public void run() {
primarySeekBarProgressUpdater();
}
};
handler.postDelayed(notification,1000);
}
}
#Override
public void onClick(View v) {
if(v.getId() == R.id.ButtonTestPlayPause){
/** ImageButton onClick event handler. Method which start/pause mediaplayer playing */
try {
mediaPlayer.setDataSource("http://www.metalgeardroid.com/music/OST.mp3"); // setup song from http://www.hrupin.com/wp-content/uploads/mp3/testsong_20_sec.mp3 URL to mediaplayer data source
mediaPlayer.prepare(); // you must call this method after setup the datasource in setDataSource method. After calling prepare() the instance of MediaPlayer starts load data from URL to internal buffer.
} catch (Exception e) {
e.printStackTrace();
}
mediaFileLengthInMilliseconds = mediaPlayer.getDuration(); // gets the song length in milliseconds from URL
if(!mediaPlayer.isPlaying()){
mediaPlayer.start();
buttonPlayPause.setImageResource(R.drawable.button_pause);
}else {
mediaPlayer.pause();
buttonPlayPause.setImageResource(R.drawable.button_play);
}
primarySeekBarProgressUpdater();
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if(v.getId() == R.id.SeekBarTestPlay){
/** Seekbar onTouch event handler. Method which seeks MediaPlayer to seekBar primary progress position*/
if(mediaPlayer.isPlaying()){
SeekBar sb = (SeekBar)v;
int playPositionInMillisecconds = (mediaFileLengthInMilliseconds / 100) * sb.getProgress();
mediaPlayer.seekTo(playPositionInMillisecconds);
}
}
return false;
}
#Override
public void onCompletion(MediaPlayer mp) {
/** MediaPlayer onCompletion event handler. Method which calls then song playing is complete*/
buttonPlayPause.setImageResource(R.drawable.button_play);
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
/** Method which updates the SeekBar secondary progress by current song loading from URL position*/
seekBarProgress.setSecondaryProgress(percent);
}
}
Override the onPause() method
#Override
public void onPause() {
if( mediaPlayer.isPlaying() ) {
mediaPlayer.stop();
}
super.onPause();
}
This method is called when the user leaves your app via the back button, home button, or if they launch another app (via notification etc)
Override the onBackPressed method and stop the player.
#Override
public void onBackPressed() {
if( mediaPlayer.isPlaying() ) {
mediaPlayer.stop();
}
super.onBackPressed();
}
Once my splash screen display for 1000ms I receive an error stating "The application has stopped unexpectedly. Please try again." It seems an activity that is supposed to start after the splash screen is not working. before the splash screen, everything worked fine. Logcat
shows the following error " E/AndroidRuntime(5480): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xxxxx.home/com.xxxxx.home.xxxxx}: java.lang.NullPointerException. I beleive the issue is with my Splash Class but cannot pin point where. Any insight would be greatly appreciated.
public class Splash extends Activity{
private final int SPLASH_DISPLAY_LENGTH = 1000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
Intent openxxxxx = new Intent("com.xxxxx.home.XXXXX");
startActivity(openxxxxx);
}
}, SPLASH_DISPLAY_LENGTH);
}
}
Here is the complete code you can use this,
package com.fsp.slideview;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.Window;
public class ImageSplashActivity extends Activity {
/**
* The thread to process splash screen events
*/
private Thread mSplashThread;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.splash);
final ImageSplashActivity sPlashScreen = this;
mSplashThread = new Thread() {
#Override
public void run() {
try {
synchronized (this) {
wait(2000);
}
} catch (InterruptedException ex) {
}
finish();
Intent intent = new Intent();
intent.setClass(sPlashScreen, SlideMainActivity.class);
startActivity(intent);
}
};
mSplashThread.start();
}
#Override
public boolean onTouchEvent(MotionEvent evt) {
if (evt.getAction() == MotionEvent.ACTION_DOWN) {
synchronized (mSplashThread) {
mSplashThread.notifyAll();
}
}
return true;
}
}