Please I need help!!
I created an app that reads data from arduino through separate thread (ReadingProcessor) and fillings the values into readings[], then I created another separate thread that checks on the values. In this checking, if it's the first time that a warning occurs then the application sends message, else if there is previous warning readings, the application should wait till passing a warning interval
public class WarningProcessor extends Thread {
float readings[];
float[] min, max;
long elapsedTime;
long[] lastWarningTime;
boolean[] inWarning;
long checkInterval = Long.parseLong(Settings.Swarning) * 60000;
long currentTime;
SerialActivity sa = new SerialActivity();
WarningProcessor(float readings[]) {
this.readings = readings;
}
#Override
public void run() {
sleep_s(2);
synchronized (readings) {
lastWarningTime = new long[readings.length];
inWarning = new boolean[readings.length];
Arrays.fill(inWarning, false);
}
while (true) {
this.readings = ReadingProcessor.readings;
synchronized (readings) {
for (int i = 0; i < readings.length; i++) {
currentTime = Calendar.getInstance().getTimeInMillis();
if (readings[i] > 100) { //here to make boundaries
if (inWarning[i] == false) {
//send warning
for(String number : StartPage.phoneNumbers)
SmsManager.getDefault().sendTextMessage(number,
null,"Warning "+readings[i], null, null);
lastWarningTime[i] = currentTime;
inWarning[i] = true;
} else {
if (currentTime - lastWarningTime[i] > checkInterval) {
//send warning
for(String number : StartPage.phoneNumbers)
SmsManager.getDefault().sendTextMessage(number,
null,"Warning "+readings[i], null, null);
lastWarningTime[i] = currentTime;
}
}
} else {
inWarning[i] = false;
}
}
}
sleep_s(1);
}
}
In case of continuous warning data the program should sends message in interval, and this works well when I'm still on activity and also when I'm onpause() state, but the problem is that after the onpause() when I return to application UI , the program resends messages in case of continuous interval, discarding the waiting till passing the interval
public class SerialActivity extends Activity {
private static ArduinoSerialDriver sDriver;
private static TextView mDumpTextView;
private static ScrollView mScrollView;
String Data[]={"Temperature"};
float[] readings = new float[Data.length];
ReadingProcessor readingProcessor;
WarningProcessor warningProcessor;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.serialactivity);
mDumpTextView = (TextView) findViewById(R.id.consoleText);
mScrollView = (ScrollView) findViewById(R.id.demoScroller);}
#Override
protected void onStart() {
super.onStart();
ReadingProcessor rp = new ReadingProcessor(readings,sDriver);
readingProcessor=rp;
WarningProcessor wp = new WarningProcessor(readings);
warningProcessor=wp;
rp.start();
wp.start();
}
#SuppressWarnings("deprecation")
#Override
protected void onDestroy() {
super.onDestroy();
readingProcessor.Stop();
warningProcessor.stop();
}
So please help me, I tried too many solutions like using handler and I got the same problem
onStart is called every time you return the application to the foreground. Your problem is that you have multiple instances of each thread running. If you only want one instance of each thread running, you need to create and start the threads in onCreate instead of onStart. In general, you should only start a thread in onStart if you are going to kill it in onPause.
Related
I'm getting java.lang.IllegalStateException in my Android Music Player Application every time when I closes the Activity
mCurrentPosition = mediaPlayer.getCurrentPosition()/1000; // In milliseconds
I've tried nearly all the codes available and even all at java.lang.illegalStateException randomly occurs when getting mediaPlayer.getCurrentPosition also
Here's my Java code where I'm using it:
protected void initializeSeekBar(){
mSeekBar.setMax(mediaPlayer.getDuration()/1000);
mRunnable = new Runnable() {
#Override
public void run() {
int mCurrentPosition;
if(mediaPlayer!=null && mediaPlayer.isPlaying()){
mCurrentPosition = mediaPlayer.getCurrentPosition()/1000; // In milliseconds
}
else {
mCurrentPosition = 0;
}
if (mSeekBar != null) {
mSeekBar.setProgress(mCurrentPosition);
getAudioStats();
}
handler.postDelayed(mRunnable,1000);
}
};
handler.postDelayed(mRunnable,1000);
}
Please Help me out of this. Thanks in Advance
Edit 1
Also, my Seekbar goes to start when the music pauses and on play, it continues from where it was before pausing
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
getAudioStats();
initializeSeekBar();
if(mediaPlayer != null && fromUser) {
mediaPlayer.seekTo(progress * 1000);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
protected void getAudioStats(){
long duration = mediaPlayer.getDuration()/1000; // In milliseconds
long due = (mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition())/1000;
long pass = duration - due;
String test = DateUtils.formatElapsedTime(pass);
String test1 = DateUtils.formatElapsedTime(due);
current_time.setText("" + test);
//mDuration.setText("" + duration + " seconds");
total_time.setText("" + test1);
}
You need to remove your runnable from the handler queue when the activity closes (or, better yet, when it pauses). Try putting this in your activity's onPause() method:
handler.removeCallbacks(mRunnable);
For additional robustness, inside the runnable itself, you should only re-queue the runnable if the activity is still active. So instead of this:
handler.postDelayed(mRunnable,1000);
you should do this (assuming this code is in the activity class):
if (!isDestroyed()) {
handler.postDelayed(mRunnable,1000);
}
Also make sure you are stopping the media player before the activity is destroyed.
P.S. If you call initializeSeekBar() multiple times, you will be reassigning mRunnable and leaving the old one in the handler queue where it can cause trouble later. To fix this, you should add this at the start of initializeSeekBar():
protected void initializeSeekBar(){
if (mRunnable != null) {
handler.removeCallbacks(mRunnable);
}
// ... the rest of the method that you currently have
I am making a Map based app where users would often load over 10k polygons on the map. The only problem is that the only way to add a polygon to the map is in the UI thread, which means when I add them it will either freeze for 5 - 10 seconds or it will crash.
I'm ready to accept that it will just have to take time to load, but is there a way I can slow down the for loop when the system is struggling to prevent the crashing and even the freezing? One method I have thought of is putting a short delay on the for loop, but that will be less than ideal as it will have to take much longer then it has to to be on the safe side.
protected void onPostExecute(HashMap<String, ArrayList> result){
for(String key : result.keySet()){
List<PolygonOptions> thisList = result.get(key);
for(PolygonOptions poly: thisList){
Polygon thisPoly = mMap.addPolygon(poly);
}
}
}
Here there is a pseudo code about how I solve this:
private final Handler handler_render_data = new Handler ();
private int actualItemRendering;
private static final int HANDLER_RUN_DELAY = 1000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the message telling the user to wait
// This Linear Layout includes a text and cover all teh screen
lyt_report_progress = (LinearLayout) findViewById (R.id.lyt_report_progress);
lyt_report_progress.setVisibility (View.VISIBLE);
lyt_report_progress.requestFocus ();
lyt_report_progress.setClickable (true);
// Your code calling your async task
}
// Your callback from your async task
private void callbackHere (Data myData) {
this.localMyData = myData;
// You store your data locally and start the rendering process
actualItemRendering = 0;
handler_render_data.post (createDataFromTaskResult);
}
private Runnable createDataFromTaskResult = new Runnable () {
#Override
public void run () {
if (actualItemRendering < myData.length ()) {
// Render your data here
// Continue with the next item to render
actualItemRendering++;
handler_render_data.post (createDataFromTaskResult);
} else {
// All fields were rendered
handler.postDelayed (hideProgressBarTask, HANDLER_RUN_DELAY);
}
}
};
private Runnable hideProgressBarTask = new Runnable () {
#Override
public void run () {
lyt_report_progress.setVisibility (View.GONE);
}
};
Hope it helps you.
Split it into several tasks and execute each task on main thread separately. I.e.
for (int i = 0; i < 20; ++i) {
runOnUiThread(new Runnable() { .. process 1/20 of your work });
}
You don't need to add a delay. Also you can experiment with granularity, probably better to increase it from 1/20.
I have a major problem about changing the value from a constructor
This is an app for flashlights. It will connect to a site to check the interval value (ex. 500 ms) and it will store it to an variable named frum_timer every 2 seconds.
Here's a object for that.
(also it will update a boolean if there's a new value)
FlashActivity = new CountDownTimer(40000, frum_timer) {
#Override
public void onTick(long millisUntilFinished) {
stats_of_run = true;
if (bool) {
final_form.setText("\\Flash ON//");
// CAMERA INSTRUCTIONS FOR OPENING FLASH
bool = false;
frumtimer_stats.setText("Speed:" + frum_timer);
} else {
stats_of_run = true;
final_form.setText("->Flash OFF-<");
// CAMERA INSTRUCTIONS FOR CLOSING FLASH
bool = true;
}
}
#Override
public void onFinish() {
}
}.start();
I made another CountDownTimer object with a refresh rate of 200 seconds to make sure the frum_timer from FlashActivity object will take change.
and using this
frumtimer_stats.setText("Speed:" + frum_timer);
in FlashActivity for displaying the variable.
However, after the variable frum_timer is changed, the FlashLight keep going again and again at the same old speed even if a made an FlashActivity.cancel() followed by FlashActivity.start()
Can someone give me some help?
Full link of code:
https://mycodestock.com/public/snippet/14395
Summary:
1.You start the app.
2. Refresh countdown starts in 2 sec
3. When there is a frum_timer the FlashActivity will start. After 2 sec, if there is another value stored on frum_timer, the actual FlashActivity will be canceled and will start a new one.
4.The problem is the new FlashActivity start but with the old frum_timer
I used:
public void startProgress(View view) {
// do something long
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 20; i++) {
final int value = i;
doFakeWork();
progress.post(new Runnable() {
#Override
public void run() {
// text.setText("Updating");
progress.setMax(20);
progress.setProgress(value);
}
});
}
}
};
new Thread(runnable).start();
}
private void doFakeWork() {
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mProgressBar = (ProgressBar)findViewById(R.id.adprogress_progressBar);
final Thread timerThread = new Thread() {
private volatile boolean running = true;
public void terminate() {
running = false;
}
#Override
public void run() {
while(running) {
mbActive = true;
try {
int waited = 0;
while(mbActive && (waited < TIMER_RUNTIME)) {
sleep(200);
if(mbActive) {
waited += 200;
updateProgress(waited);
}
}
} catch(InterruptedException e) {
running=false;
}
}
}
};
timerThread.start();
}
public void onLocationChanged(Location location) {
if (location != null) {
TextView text;
text = (TextView) findViewById(R.id.t2);
String str= "Latitude is " + location.getLatitude() + "\nLongitude is " + location.getLongitude();
text.setText(str);
text.postInvalidate();
}
}
How would I stop the thread in onCreate from onLocationChanged? I need to stop the progressbar once the GPS provides the coordinates. I need to join the threads using join(). Solution will be helpful.
You can simply declare in your Activity a member :
private Thread mTimerThread = null;
then in your onCreate() replace :
final Thread timerThread = new Thread() {
with
mTimerThread = new Thread() {
and in onLocationChanged :
if (mTimerThread != null && mTimerThread.isAlive()) {
mTimerThread.terminate();
}
to achieve what you want.
However, as others mentioned, I would also recommend using custom AsyncTask as it would be most clear way of threading in your case.
Make timerThread a class member and not a locale variable, in this way you should access it from the onLocationChanged method
Use AsyncTask instead, store the Future and stop the thread yourself.
If this is not a home work assignment, then I see no need to join(). Even more so when you're trying to join the UI thread with an arbitrary thread, effectively casuing an ANR.
Either:
Create you own class extending Thread, implement your terminate() method, and then call it whenever you want.
Create your own class extending AsyncTask, implementing LocationListener, and use its onProgressUpdate() method.
I have an android application (written in java) which has two buttons (connect and request data).
When each button is clicked, a task is performed and a progress dialog appears to display how much the task has completed.
In order to show the progress dialog, when each button is clicked, the task is run on a thread.
The connect button just has one task - run on the thread. However, the request data button executes two tasks - the first task on the thread similar to the connect button but also a second task, refreshInfo() which must be run after the first task on the thread, progThread is finished.
private Button connectButton;
private Button requestDataButton;
private ProgressDialog connectionDialog;
private ProgressDialog requestDataDialog;
private ProgressThread progThread;
private int currentDialog;
public void connectClick(View view) //When the connect button is clicked
{
performAction(1); //Run the thread to perform the action
}
public void requestDownloadClick(View view) //When the request data button is clicked
{
performAction(2); //Run the thread to perform the action
refreshInfo(); //Do something else
}
private void performAction(int type)
{
currentDialog = type;
showDialog(type);
try
{
progThread.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
The key method here is performAction(int type). I basically don't want this method to complete until progThread has finished running.
As you can see, I've tried progThread.join() to prevent the method from continuing until progThread has finished running, however as progThread involves displaying a Progress Dialog, running progThread.join() seems to prevent the Progress Dialog from showing, as currently when you click the button, the first task is performing but the dialog only flashes up at the end.
Can anyone think of a way to run the thread, showing the Progress Dialog as normal and then running the second method (if there is one).
I've included the thread code below incase it is needed.
private class ProgressThread extends Thread
{
final static int DONE = 0;
final static int RUNNING = 1; // Class constants defining state of the thread
private Handler progressHandler;
int mState;
int total;
ProgressThread(Handler _handler) // Constructor with an argument that specifies Handler on main thread to which messages will be sent by this thread.
{
progressHandler = _handler;
}
public void run() // Invoked automatically when the Thread starts.
{
mState = RUNNING;
updateProgressBar();
connectButton = (Button) findViewById(R.id.btnConnect);
requestDataButton = (Button) findViewById(R.id.btnRequestDownload);
while (mState == RUNNING)
{
if (currentDialog == 1)
{
try
{
doSomething();
if (something)
{
setState(DONE);
total = 100;
updateProgressBar();
removeDialog(1);
connectButton.setEnabled(false);
}
else
{
total = total + 20;
if (something has reached a limit)
{
setState(DONE);
total = 0;
updateProgressBar();
removeDialog(1);
}
}
updateProgressBar();
}
catch (Exception e)
{
}
}
if (currentDialog == 2)
{
try
{
doSomething();
total = 10;
updateProgressBar();
doSomething();
total = 70;
updateProgressBar();
if (something) //If the download info has not been got
{
setState(DONE);
total = 0;
updateProgressBar();
removeDialog(2);
runOnUiThread(new Runnable()
{
public void run()
{
connectButton.setEnabled(true);
requestDataButton.setEnabled(true);
}
});
}
else
{
total = 100;
updateProgressBar();
setState(DONE);
removeDialog(2);
runOnUiThread(new Runnable()
{
public void run()
{
requestDataButton.setEnabled(false);
}
});
}
}
catch (Exception e)
{
removeDialog(2);
setState(DONE);
runOnUiThread(new Runnable()
{
public void run()
{
connectButton.setEnabled(true);
requestDataButton.setEnabled(true);
}
});
}
}
}
}
// Set current state of thread (use state=ProgressThread.DONE to stop thread)
public void setState(int state)
{
mState = state;
}
public void updateProgressBar()
{
Message msg = progressHandler.obtainMessage(); // Send message (with current value of total as data) to Handler on UI thread so that it can update the progress bar
Bundle b = new Bundle();
b.putInt("total", total);
msg.setData(b);
progressHandler.sendMessage(msg);
}
}
final Handler handler = new Handler() // Handler on the main (UI) thread that will receive messages from the second thread and update the progress.
{
public void handleMessage(Message msg)
{
int total = msg.getData().getInt("total"); // Get the current value of the variable total from the message data and update the progress bar
switch (currentDialog)
{
case 1 :
connectionDialog.setProgress(total);
break;
case 2 :
requestDataDialog.setProgress(total);
break;
}
}
};
protected Dialog onCreateDialog(int id)
{
switch (currentDialog)
{
case 1 :
connectionDialog = new ProgressDialog(this);
connectionDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
connectionDialog.setMax(100);
connectionDialog.setProgress(0);
connectionDialog.setMessage("Connecting To The Device");
progThread = new ProgressThread(handler);
progThread.start();
return connectionDialog;
case 2 :
requestDataDialog = new ProgressDialog(this);
requestDataDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
requestDataDialog.setMax(100);
requestDataDialog.setProgress(0);
requestDataDialog.setMessage("Requesting Download Data");
progThread = new ProgressThread(handler);
progThread.start();
return requestDataDialog;
default :
return null;
}
}
Android API provides an AsyncTask class which has two methods doInBackground and onPostExecute. You'll have to override both of them, do whatever you have to do in doInBackground and when the job is done onPostExecute callback will be run.
There's also an onProgressUpdate callback which is exactly what you need.
Look at AsyncTask class. It should be able to do what you want.
http://developer.android.com/reference/android/os/AsyncTask.html
Seems other answers have you covered. AsyncTask is the way to go.
However if you want to push through with your Thread implementation, just start() the next thread at the end of the first thread's run method.
Sounds like you need to use a CountdownLatch of size 1