I'm having trouble with my app. What I want is:
MainActivity launches & creates a scheduled thread which periodically checks whether the WiFi service is enabled. If it IS, go to a new activity. If it ISN'T then launch a warning & take the user to the WiFi settings page.
When the user comes back to the Main Activity, the MainActivity code will now sense the WiFi service is enabled & send them to the second activity.
I have this working. Here's the code:
#Override
protected void onResume()
{
super.onResume();
ScheduledExecutorService oScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
try
{
oScheduledExecutor.scheduleAtFixedRate({RUNNABLE HERE}, 0, 5, TimeUnit.SECONDS);
}
catch (Exception e)
{
System.out.println("(MainActivity) Caught Exception here. #1");
System.out.println("(MainActivity) Error: " + e.getMessage() + " Cause: " + e.getCause());
e.printStackTrace();
}
}
#Override
protected void onStart()
{
super.onStart();
// Assign WifiManager to System service
oWiFiManager = (WifiManager) getSystemService(WIFI_SERVICE);
// Create Runnable
oWiFiUpdater = new Runnable() {
#Override
public void run()
{
// If we should show WiFi Disabled
if (shouldShowWiFiAlert())
{
runOnUiThread(new Runnable() {
#Override
public void run() {
launchWiFiDisabledAlert();
}
});
}
Intent oAPListIntent = new Intent(getApplicationContext(), APList.class);
startActivity(oAPListIntent);
}
}
};
However when we are on the second activity, the first thread is still running. I thought that when the Activity is removed from View, all threads cease running??
I want the executor to only run when the Activity is viewable! Any ideas!?
EDIT: Answer thanks to inspiration from njzk2
#Override
protected void onResume()
{
super.onResume();
createWiFiAlertDialog();
boolean bWiFiEnabling = wifiEnabling();
while (bWiFiEnabling)
{
try
{
doSyncedWait(500);
}
catch (Exception e)
{
System.out.println("(MainActivity) Exception caught waiting. " + e.getMessage());
}
bWiFiEnabling = wifiEnabling();
}
boolean bWiFiEnabled = wifiReady();
if (!bWiFiEnabled)
{
runOnUiThread(new Runnable() {
#Override
public void run() {
AlertDialog oAlertDialog = m_oAlertDialog;
oAlertDialog.show();
}
});
}
else
{
Intent oIntent = new Intent(this,APList.class);
startActivity(oIntent);
}
}
private boolean wifiEnabling()
{
WifiManager oWiFiManager = m_oWiFiManager;
if (oWiFiManager == null) return false;
if (oWiFiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) return true;
return false;
}
private boolean wifiReady()
{
WifiManager oWiFiManager = m_oWiFiManager;
if (oWiFiManager == null) return false;
// If the WiFi state is anything other than enabled, then wait.
if (oWiFiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) return true;
return false;
}
If you give your runnable a reference to the activity, and set a boolean to true in onResume() and false in onPause(), you should be able to reference the boolean from your runnable and then use a if statement to only run if the boolean is set to true.
Related
I am trying to play with progress bars. I have this (below) simple activity which runs a progress bar N times one after the other, when I call Progress(N). It is working great but the problem I am facing is, if I press back button. I get into the mainActivity but the progress bars (the threads) are still running in background one after the other. As soon as they finish N loops, the intent is called and whatever I would be doing would be interrupted by this LOOP_OVER activity.
I tried solving this by my own. I tried using variable of Thread class (before I was directly doing it). And tried to interrupt() it at onDestroy() or even just before the intent is called but its not helping. How should I go about it?
public class Loop extends Activity {
private ProgressBar progressBar;
private CircleProgress circleProgress;
private int progressStatus = 0;
private Handler handler = new Handler();
private TextView myView;
private int started = 0, doneLoop=0;
private Thread th;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loop);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
circleProgress = (CircleProgress) findViewById(R.id.circle_progress);
myView = (TextView) findViewById(R.id.instruction);
progressBar.setScaleY(3f);
// Start long running operation in a background thread
Progress(3);
}
#Override
public void onDestroy() {
// Below, everything I am just
th.interrupt();
Loop.this.finish();
Thread.currentThread().interrupt();
super.onDestroy();
}
public void Progress(final int numberOfRuns){
// QueView.setText(Que);
if(numberOfRuns == 0){
th.interrupt();
Intent myIntent = new Intent(Loop.this, LOOP_OVER.class);
startActivity(myIntent);
super.onDestroy();
finish();
}
th = new Thread(new Runnable() {
public void run() {
genNextSet();
while (progressStatus < 100) {
progressStatus += 1;
// Update the progress bar and display the
//current value in the text view
handler.post(new Runnable() {
public void run() {
circleProgress.setProgress(progressStatus);
progressBar.setProgress(progressStatus);
textView.setText(progressStatus+"/"+progressBar.getMax());
}
});
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
myView.setText(Que);
}
});
// Sleep for 200 milliseconds.
//Just to display the progress slowly
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
progressStatus = 0;
Progress(numberOfRuns - 1);
}
});
th.start();
}
private void genNextSet() {
// so some cool here!
}
}
You can think of a class variable that is shared among all threads.
Try to add something like this:
private Boolean LOOP = true;
then
while (progressStatus < 100 && LOOP) {
and
#Override
public void onBackPressed() {
LOOP = false
}
also
if(LOOP == true){
// call intent
}
finish();
Your activity does not get destroyed, if you press the "Back"-key, thus onDestroy() will not be called.I'd override onBackPressed(), if I where you.Alternatively, you could try to put it into the onPause()-method.
You haven't override the back button pressed..try this
#Override
public void onBackPressed() {
th.interrupt();
Loop.this.finish();
Thread.currentThread().interrupt();
super.onBackPressed();
// add finish() if you want to kill current activity
}
I want to call adapter.notifyDataSetChanged() from another thread. I read that I should use an AsyncTask and do the adapter.notifyDataSetChanged() in post execute.
I must execute the AsyncTask every 5 seconds only on the current activity (might be parent or child activity) because only one activity can do the asynctask at the same time.
Should I create a TimerTask which executes the AsyncTask every 5 seconds, stop it when I start another activity and start it back in onResume ?
Here is my code for the thread which updates the ListView of the current Activity.
private void runEventHandler() {
new Thread() {
public void run() {
while (true) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
users.add(new User(10, "a", false));
adapter.notifyDataSetChanged();
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
Now I must be able to update the child activities' ListViews when a new User is added.
one possible way is that you create a flag in both activity to control your threads to be run ( the following codes are not runable just example to understand what you can do):
Activity A
{
public static boolean stopThread = false;
#Override
public void onResume()
{
super.onResume();
// put your code here...
stopThread =false;
runEventHandler();
}
private void runEventHandler() {
new Thread() {
public void run() {
while (A.stopThread != false) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
users.add(new User(10, "a", false));
adapter.notifyDataSetChanged();
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
#Override
protected void onStop(){
super.onStop();
stopThread =true;
}
}
Activity B
{
public static boolean stopThread = false;
#Override
public void onResume()
{
super.onResume();
// put your code here...
stopThread =false;
runEventHandler();
}
private void runEventHandler() {
new Thread() {
public void run() {
while (B.stopThread != false) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
users.add(new User(10, "a", false));
adapter.notifyDataSetChanged();
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
#Override
protected void onStop(){
super.onStop();
stopThread =true;
}
}
also you can use onPause() instead of onStop(). depends on your program concept.
You should a timertask like in link below : https://examples.javacodegeeks.com/android/core/activity/android-timertask-example/
the code to post any change on UIThread if you are in a different thread like doInBackground of AsyncTask:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Here you can set your Ui Components
}
});
I am trying to do this simple task. I have two buttons called START and STOP, I want to execute some task in loop by clicking on START and want to exit from this loop by clicking STOP.
Code-
public class DrawPath extends Activity implements View.OnClickListener {
ArrayList<LatLng> positions = new ArrayList<LatLng>() ;
static int c=1;
Location location;
GoogleMap mMap;
Button btStart,btStop;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.drawpath);
initializeVar();
btStart.setOnClickListener(this);
btStop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
c = 0;
System.out.println("tested2");
}
});
}
private void initializeVar()
{
btStart=(Button)findViewById(R.id.btStart);
btStop=(Button)findViewById(R.id.btStop);
}
#Override
public void onClick(View v) {
getupdate(1);
}
private void getupdate(int d) {
c = d;
CurrentPosition currentPosition = new CurrentPosition(this);
if (c == 0) {
System.out.println("Done");
} else {
location = currentPosition.getCurrentLocation();
LatLng pos = new LatLng(location.getLatitude(), location.getLongitude());
positions.add(pos);
System.out.println("running");
try {
Thread.sleep(5000);
getupdate(c);
} catch (Exception e) {
}
}
}
}
Somebody please share any idea how to achieve it.
You can use Handler with Runnable to stop your thread after STOP button click.
I am giving you hint use following code according to your requirement
Handler handler = new Handler();
Runnable runable = new Runnable({
#Override
public void run(){
// count
handler.postDelayed(this, 1000);
}
});
Now you can call following line from your btnStop.onClick().
handler.removeCallbacks(runable);
Check this for more details on Handler and Runnable
What I suggest it create a inner class which extends Thread and according to user's action start and stop the thread. here is an example
class DrawPath extends Activity implements View.OnClickListener {
MyThread thread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawpath);
initializeVar(); //not in my code so you add it
btStart.setOnClickListener(this);
btStop.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btStart:
if (thread == null) {
thread = new MyThread();
thread.start();
}
break;
case R.id.btStop:
if (thread != null) {
thread.interrupt();
}
break;
}
}
class MyThread extends Thread {
#Override
public void run() {
while (true) {
try {
Thread.sleep(3000);
//your stuff goes here or before sleep
} catch (InterruptedException e) {
e.printStackTrace();
thread = null;
break;
}
}
}
}
//whey interrupt here bcz infinite loop will be running until and unless you stop it.
#Override
protected void onDestroy() {
super.onDestroy();
if (thread != null)
thread.interrupt();
}
}
I saw your code which needs little more improvements that's why I wrote this big file :)
Suggestions :
Checkout the implementation of onClickListener.
Stopping thread at onDestroy() because thread will be running even after you close your application, so you need to stop when you
come out (destroyed) of your main activity.
I'm trying to show a ProgressDialog while I'm processing some data on background.
I call the method show() before starting the Thread, and it doesn't show, but when i call inside the Thread the method dismiss(), it appears and desapears in a flash.
I read some about using an Async Task, but I really don't want to show a progress, just the spinning that ads the user that the app is loading.
How can I solved this?
Some of my code:
// When clicking a button a call this method to start the thread
public void onClick(View v) {
// Here, doesn't show the spinning wheel
progress = ProgressDialog.show(this,
"Wait please …",
"Scanning …",
true);
Thread scan = new Thread(new Runnable() {
#Override
public void run() {
runOnUiThread(new Scanner());
progress.dismiss();
}
});
scan.start();
}
I declared the progress var like this:
private ProgressDialog progress;
public void onCreate(Bundle savedInstanceState) {
//[...]
progress = new ProgressDialog(this);
//[...]
}
The Scanner class code:
private class Scanner implements Runnable {
private final String TAG = "SCANNER-->";
public void run() {
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
for (int i = 0; i < 10; i++) {
wifiManager.startScan();
List<ScanResult> results = wifiManager.getScanResults();
if (results != null) {
final int size = results.size();
if (size == 0) {
adapter.clear();
adapter.add("No access points in range");
break;
}
else {
txt.setText("Number of results: " + results.size());
Log.d(TAG,"Number of results: " + results.size());
for (ScanResult result : results) {
if (adapter.getPosition(result.SSID) == -1) {
adapter.add(result.SSID);
}
}
}
}
else {
adapter.clear();
adapter.add("No results. Check wireless is on");
break;
}
adapter.notifyDataSetChanged();
Log.d(TAG,"sistema avisado de cambios");
// Refresh information each 0.5 second
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
progress.dismiss();
}
}
How you can see I'm refreshing a List with nearly networks.
Try this:
progress = ProgressDialog.show(this, "dialog title",
"dialog message", true);
See documentation - static show(...) methods.
http://developer.android.com/reference/android/app/ProgressDialog.html
I'm new to Android development and I need some help with a little problem.
I have a background Service that runs my media player and communicate with my PlayerActivity.
So far so good.
I need to schedule the execution of the tracks in different periods. i.e Play track x for one minute than play track y for 30 seconds etc.
So I call MyTimer thread form the PlayerActivity, this thread throws event at the specific time,
the PlayerActivity catches the Event and calls the MediaplayerService next() method.
My Problem is if I call next() without the thread it works fine, If i call it with the thread I get
mContext is null, can't getMirrorDisplayStatus!!!
with mediaplayer warning (1, 902)
I've tried to run this thread with from the PlayerActivity via Handler.post() and runOnUiThread()
and I get the same error.
below is the code for MyTimer Thread.
public class MyTimer implements Runnable {
private Object mPauseLock;
private boolean mPaused;
private boolean mFinished;
private TimeSection section;
public Trainer()
{
mPauseLock = new Object();
mPaused = false;
mFinished = false;
BusProvider.getInstance().register(this);
}
#Override
public void run()
{
while (!mFinished)
{
TimerManager tm = TimerManager.getInstace();
this.section = tm.getCurrentTimeSection();
if(this.section == null)
mFinished = true;
else
{
tm.inc();
// produce sectionChangeEvent event
BusProvider.getInstance().post(produceSectionEvent());
try
{
Thread.sleep((this.section.getTypeDuration() * 1000));
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized (mPauseLock)
{
while (mPaused)
{
try
{
mPauseLock.wait();
} catch (InterruptedException e)
{
}
}
}
}
}
/**
* Call this on pause.
*/
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
/**
* Call this on resume.
*/
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
#Produce public TimeSectionEvent produceSectionEvent(){
return new TimeSectionEvent(this.section);
}
}
some code of the Player Activity:
public class PlayerActivity implements
IMediaPlayerServiceClient{
private MediaPlayerService mService;
....
/**
* Binds to the instance of MediaPlayerService. If no instance of
* MediaPlayerService exists, it first starts a new instance of the service.
*/
public void bindToService()
{
Intent intent = new Intent(this, MediaPlayerService.class);
if (MediaPlayerServiceRunning())
{
// Bind to LocalService
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
} else
{
startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
}
.....
/*
* This is how I start the timing thread
*/
private void startTiming()
{
mTimer = new MyTimer();
runOnUiThread(mTimer);
// trainingHandler.post(mTrainer);
}
public void next(TimeSection section)
{
mService.next(section);
}
/*
* Here I catch the TimeSectionEvent from MyTimer thread
*/
#Subscribe public void onSectionChanged(TimeSectionEvent e)
{
TimeSection section = e.getSection();
if(section != null)
next(section);
}
each activity has context so from the exception that you got i guess its a problem with the context of the MediaPlayerService.
you are using bindService(...) to bind the intent to the MediaPlayerService that should bind the context.
try to check if that binding is still there when you are trying to do "mService.next(section);"
Problem SOLVED!
The problem was that I was that the timing thread was running on the UI thread -> calling Thread.sleep made the UI thread sleeping as well.
So I end up using IntentService that doing the timer thread job in background.
public class TimingService extends IntentService{
private Object mPauseLock;
private boolean mPaused;
private boolean mFinished;
private TimeSection section;
public TimingService()
{
super("TimingService");
mPauseLock = new Object();
mPaused = false;
mFinished = false;
BusProvider.getInstance().register(this);
}
#Override
protected void onHandleIntent(Intent intent)
{
while (!mFinished)
{
TimerManager tm = TimerManager.getInstace();
this.section = tm.getCurrentTimeSection();
if(this.section == null)
mFinished = true;
else
{
tm.inc();
// produce sectionChangeEvent event
BusProvider.getInstance().post(produceSectionEvent());
try
{
Thread.sleep((this.section.getTypeDuration() * 1000));
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized (mPauseLock)
{
while (mPaused)
{
try
{
mPauseLock.wait();
} catch (InterruptedException e)
{
}
}
}
}
}
/**
* Call this on pause.
*/
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
/**
* Call this on resume.
*/
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
#Produce public TimeSectionEvent produceSectionEvent(){
return new TimeSectionEvent(this.section);
}
#Subscribe
public void onPauseEvent(PauseEvent e)
{
this.onPause();
}
#Subscribe
public void onResumeEvent(ResumeEvent e)
{
this.onResume();
}
}