I have a problem with my onCreate method. I have identified that when I switch to this activity the onCreate method gets called twice and therefore starting 2 threads which I dont want. Because the thread sends coordinates to a RaspberryPi and the 2nd unwanted thread always sends 0 0 0 which I dont want. I cant seem to find a fix for this so . . . I'd appreciate help if someone could tell me a fix so the thread starts only once.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Joystick = (ImageView) findViewById(R.id.Joystick);
Regler = (ImageView) findViewById(R.id.Regler);
buttonFoto = (Button) findViewById(R.id.buttonFoto);
buttonVideo = (Button) findViewById(R.id.buttonVideo);
buttonNeu = (Button) findViewById(R.id.buttonNeu);
buttonSpeichern = (Button) findViewById(R.id.buttonSpeichern);
touchscreenJoystick = (TextView) findViewById(R.id.touchscreenJoystick);
touchscreenJoystick.setOnTouchListener(this);
touchscreenRegler = (TextView) findViewById(R.id.touchscreenRegler);
touchscreenRegler.setOnTouchListener(this);
RL = (RelativeLayout) findViewById(R.id.activity_main);
running = true;
firstTouch = true;
Bild = (WebView) findViewById(R.id.webView);
Bild.loadUrl("http://10.0.0.1:8080/stream");
thread = new Thread(new MainActivity.TransmitThread());
thread.start();
}
EDIT:
I tried something with SaveInstanceState
//Same onCreate-stuff as above
if(savedInstanceState == null)
{
thread = new Thread(new MainActivity.TransmitThread());
thread.start();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putString("message","crashed");
super.onSaveInstanceState(outState);
}
what this does is weird. Now I only have one thread that crashes immediately after sending the coordinates once.
Logs:
Log.i that i put before sending:
I/sent: //X: 0 //Y: 0 //Z: 0
Log that comes right after
I/System: core_booster, getBoosterConfig = false
Edit 2:
I've also tried starting the thread at an other timing. In my onTouch like this:
public boolean onTouch(View v, MotionEvent me)
{
xt = me.getX();
yt = me.getY();
int Aktion = me.getAction();
if(firstTouch)
{
thread = new Thread(new MainActivity.TransmitThread());
thread.start();
firstTouch = false;
}
//other stuff that i need to do here
}
But this results into the same as my try with SaveInstanceState a thread that transmits once but doesnt loop.
Edit 3:
I should probably post my thread too
class TransmitThread implements Runnable
{
#Override
public void run()
{
while(running)
{
delay();
xss = xs;
yss = ys;
zss = zs;
Log.i("sent","//X: " + xss + " //Y: " + yss + " //Z: " + zss);
transmit();
}
}
public void transmit()
{
try{
socket = new Socket(ServerIP,ServerPort);
OutputStream outputStream = socket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
printStream.print(xs + " " + ys + " " + zs);
Akkustand = input.readLine();
handler.sendEmptyMessage(0);
}catch(UnknownHostException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
public void delay(){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
FINAL EDIT:
I managed to do a workaround. I check before sending if the value is 0 if it is then I change it to 200. On the other end I check if its 200 and change it to 0 and ignore any 0 that I get.
First of all OnCreate will only be called one time for each lifetime of the Activity. However, there are a number of situations that can cause your activity to be killed and brought back to life. Thus, OnCreate get called again.
First thing you can debug the code and find the place where it called repeatedly.
Note: To avoid this situation you can save state information in onSaveInstanceState and restore it back in the state bundle you get in on create.
Thanks
OnCreate() already creates a main thread, and then you call another instance of the main class by manually creating a thread of the main class.
According to this answer all you dont need boolean check, just check if savedInstance is null, and only then start the second thread.
More general solution would be to initialise and start the thread in onStart() but dont forget to stop it in onStop() . If you want this thread to be long running in the background- I suggest start using something else- Service docs
Any configuration change will cause Android to restart your Activity like screen rotation, keyboard availability etc. what the system is actually doing is calling onDestroy() and then immediately calling onCreate(), meaning that the original Activity object is replaced by a new one without any knowledge of the executing background thread, so only the Activity object that started the thread knows that the thread was started.
A better way of handling this is through retaining thread in Activity.
The Activity class contains two methods for handling thread retention:
public Object onRetainNonConfigurationInstance()
called before configuration change occurs
public Object getLastNonConfigurationInstance()
Called in the new Activity object to retrieve the retained object returned in onRetainNonConfigurationInstance()
So you can implement this in following way.
private static MyThread t;
#Override
public void onCreate(Bundle savedInstanceState) {
Object retainedObject = getLastNonConfigurationInstance();
if (retainedObject != null) {
t = (MyThread) retainedObject;
}
else{
t = new MyThread();
t.start();
}
}
#Override
public Object onRetainNonConfigurationInstance() {
if (t != null && t.isAlive()) {
return t;
}
return null;
}
Related
I am having issues using another thread in Android for checking the availability of a web server.
I start a new thread to avoid:
NetworkOnMainThreadException
This is the log cat:
E/AndroidRuntime(17753): FATAL EXCEPTION: Thread-2370
E/AndroidRuntime(17753): Process: com.example.c3po, PID: 17753
E/AndroidRuntime(17753): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
E/AndroidRuntime(17753): at com.example.c3po.MainActivity$1SecondThread.run(MainActivity.java:72)
The code used in the second thread
class SecondThread extends Thread {
public void run() {
TextView pingResult = (TextView) findViewById(R.id.checkStatus); // to display result
EditText userText = (EditText) findViewById(R.id.userData); // take in user url
String result = userText.getText().toString();
try {
InetAddress address = InetAddress.getByName(result); // user input is result (a URL)
boolean b = address.isReachable(3000);
String str = String.valueOf(b); // turning the value of the boolean into string
pingResult.setText(str); // value displays as true or false - LINE 72
}
catch (UnknownHostException e) {pingResult.setText("WRONG");} // will fill with helpful message later
catch (IOException e) {pingResult.setText("WRONG");}
}
And the button to trigger the thread:
Button sendPing = (Button) findViewById(R.id.pingButton);
sendPing.setOnClickListener(new OnClickListener() {
public void onClick (View activity_main) {
SecondThread thread = new SecondThread();
thread.start();
}
});
Line 72 is commented. I have tried googling the specific issue, but have got mixed results.
Any help would be appreciated.
Many thanks
You are updating ui from the background thread. You cannot do that. Ui needs to updated on the ui thread. Use AsyncTask.
You could use
runOnUiThread(new Runnable() {
#Override
public void run() {
pingResult.setText(str);
}
});
Similarly for pingResult.setText("WRONG");
But better to use AsyncTask as it would be a easier. You could do your background computation in doInBackground return result ie String in this case and update ui in onPostExecute
Edit: I put this pB = (ProgressBar) findViewById(R.id.progressBar); in the onPreExecute(). It works, everything works. But is this a good solution? I know that in my main thread the progress bar was !null. But before this findViewById, my asynctask just couldn't find the progress bar I wanted, even though I thought I was passing it in .execute().
This is my first experience with asynctask. I have a progress bar that I want to count up, but I keep getting a NullPointerException.
The log read "Progress Update: 1" but then the VM shuts down. So I know an integer is getting passed, but I can't figure out why it can't find the progress bar(pB). I've tried to setProgress(0) in the main thread, in the onPreExecute(), but the machine hated it.
It runs the rest of the for loop in doInBackground(), and logs the "Percent Progress: " and "Sleeping " but won't log any more "Progress Update: ".
The NullPointerException is at line 31, which is pB.setProgress(progress[0]);
#Override
protected void onProgressUpdate(Integer...progress){
Log.d(LOG_TAG, "Progress Update: "+progress[0].toString());
super.onProgressUpdate(progress);
if(progress[0]!=null){
pB.setProgress(progress[0]);
}
}
#Override
protected Boolean doInBackground(Integer...numSeconds){
Log.d(LOG_TAG, "doInBackground: "+numSeconds[0]);
try {
int totalSecs = numSeconds[0].intValue();
Log.d(LOG_TAG, "Total SECS: "+totalSecs);
for(int i = 1; i <= totalSecs; i++){
Log.d(LOG_TAG, "Sleeping "+i);
Thread.sleep(1000);
float percentage = ((float)i/(float)totalSecs)*100;
Log.d(LOG_TAG, "Percentage Progress: "+ percentage);
Float progress = Float.valueOf(percentage);
publishProgress(new Float(progress).intValue());
}
} catch (InterruptedException e){
e.printStackTrace();
return false;
}
return true;
}
#Override
protected void onPostExecute(Boolean result){
Log.d(LOG_TAG, "Post Execute "+ result);
super.onPostExecute(result);
pB.setProgress(0);
}
Here's some from my main thread:
To initialize the progress bar:
timer = (ProgressBar) findViewById(R.id.progressBar);
timer.setProgress(0);
To execute the asynctask:
OnClickListener startBubbles = new OnClickListener(){
#Override
public void onClick(View arg0) {
new ProgBar(timer).execute(100);
setAll();
}
};
The constructor:
public ProgBar(ProgressBar pB){
Log.d(LOG_TAG, "Constructor");
}
Null Pointer Exception occurs when you are accessing value , which is not yet been initaialized.
So for ex. char a[10];
System.out.println(a[3]);
So there must be variable within your code which you are accessing without initialising it. I thing numSecond but I am not sure.
Sorry thats all I know
i need to check a variable for change, if the change happens i will update a textview.
so i created a new thread with a while loop for this purpose. i check the variable every 1 second, via Thread.sleep()
this thread created and started in onCreate(). so it's one time.
the problem is every time i flip my phone (from vertical to horizontal or ...) a new thread will be created.
here is my code:
public class HomeActivity extends Activity
{
private final static int LOAD_SUCCESSFULL = 1;
private final long LOCATION_THREAD_SLEEP = 1000;
private boolean flag = false;
static TextView lat;
static TextView lon;
static Location currentLocation = null;
Thread locationThread;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.new_home2);
this.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.new_home_titlebar);
lat = (TextView)findViewById(R.id.t2rt3);
lon = (TextView)findViewById(R.id.t2rt4);
/* FindLocation class is a helper class that find location via simcard or gps in separate thread,
same problem happen with this thread also, it create multiple thread, for ease of work i
commented this part.
*/
//FindLocation fn = new FindLocation(this);
locationThread = new Thread(null, loadLocation, "loadLocationHomePage");
locationUpdater();
}
private static Handler locationUpdateHandler = new Handler()
{
public void handleMessage(Message msg)
{
switch(msg.what)
{
case LOAD_SUCCESSFULL:
lat.setText(Double.toString(currentLocation.getLatitude()));
lon.setText(Double.toString(currentLocation.getLongitude()));
//stopThread();
break;
}
}
};
private Runnable loadLocation = new Runnable()
{
public void run()
{
//boolean flag = false;
while(!flag)
{
if(Data.currLocation != null)
{
currentLocation = new Location(Data.currLocation);
Message msg = locationUpdateHandler.obtainMessage(LOAD_SUCCESSFULL);
locationUpdateHandler.sendMessage(msg);
//return;
flag = true;
//return;
}
else
{
try
{
Thread.sleep(LOCATION_THREAD_SLEEP);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
};
public void locationUpdater()
{
//Thread locationThread = new Thread(null, loadLocation, "loadLocationHomePage");
locationThread.start();
}
so how i can solve this?
Actually the problem is that EveryTime you flip the phone a new instance of Activity is created and because of this you on every rotation you get a call on onCreate() where you are blindly creating a new Thread and Starting the new Thread.
This is the default behavior of every Activity but we can change this re-creation of Activity by stating an attribute in AndroidManifest file for the Activity
<activity
android:name="yourPackage.ActivityName"
android:configChanges="keyboardHidden|orientation|screenSize"
</activity>
This will prevent from creation of Activity on orientation change.
You will also get these orientation event if you override
#Override
public void onConfigurationChanged(Configuration newConfig) {}
Hope this will solve this problem without implementing such a complex logic which may broke in some other uses case.
I think you aren't perhaps going about this in the most efficient way possible.
But if your question is simply, how do i prevent multiple worker threads from being spawned, you should look into a UIless fragment.
http://www.vogella.com/articles/AndroidFragments/article.html#headlessfragments1
i don't know why android doing this. if i putted my code in onResume(), then this behavior make sence but in my case, i don't know.
anyway i found a dirty solution. the idea is finding list of all thread and search them for mine, if it existed prevent to create another.
public boolean checkThreadExist()
{
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
for(int i = 0; i < threadArray.length ; i++)
{
if(threadArray[i].getName().equalsIgnoreCase("loadLocationHomePage"))
return true;
}
return false;
}
updated onCreate() :
if(checkThreadExist())
{
}
else
{
locationThread = new Thread(null, loadLocation, "loadLocationHomePage");
locationUpdater();
}
I am trying to passthrough the input obtained from the microphone to the speaker (the goal is to be able to perform audio processing in real time in the future). This is the code:
public class MainActivity extends Activity {
AudioManager am = null;
AudioRecord record =null;
AudioTrack track =null;
final int SAMPLE_FREQUENCY = 44100;
final int SIZE_OF_RECORD_ARRAY = 1024; // 1024 ORIGINAL
final int WAV_SAMPLE_MULTIPLICATION_FACTOR = 1;
int i= 0;
boolean isPlaying = true;
class MyThread extends Thread{
#Override
public void run(){
recordAndPlay();
}
}
MyThread newThread;
private void init() {
int min = AudioRecord.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
record = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, min);
int maxJitter = AudioTrack.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
track = new AudioTrack(AudioManager.MODE_IN_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, maxJitter, AudioTrack.MODE_STREAM);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setVolumeControlStream(AudioManager.MODE_IN_COMMUNICATION);
init();
newThread = new MyThread();
newThread.start();
}
#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;
}
private void recordAndPlay() {
short[] lin = new short[SIZE_OF_RECORD_ARRAY];
int num = 0;
am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
am.setMode(AudioManager.MODE_IN_COMMUNICATION);
record.startRecording();
track.play();
while (true) {
num = record.read(lin, 0, SIZE_OF_RECORD_ARRAY);
for(i=0;i<lin.length;i++)
lin[i] *= WAV_SAMPLE_MULTIPLICATION_FACTOR;
track.write(lin, 0, num);
}
}
public void passStop(View view){
Button playBtn = (Button) findViewById(R.id.playBtn);
// /*
if(!isPlaying){
record.startRecording();
track.play();
isPlaying = true;
playBtn.setText("Pause");
}
else{
record.stop();
track.pause();
isPlaying=false;
playBtn.setText("Pass through");
}
// */
}
/*
#SuppressWarnings("deprecation")
#Override
public void onDestroy(){
newThread.stop();
}
*/
#Override
protected void onDestroy() {
android.os.Process.killProcess(android.os.Process.myPid());
// killProcess(android.os.Process.myPid());
}
}
Brief overview:
The while(true) {} infinite loop in recordAndPlay() function continuously reads raw audio samples from the microphone and outputs the raw samples to the speaker. recordAndPlay() is called from a Thread started in the onCreate() function. So it starts sending the input on the microphone to the speaker as soon as the program starts (well actually after a few seconds lag but I think this latency in unavoidable). I also have a button that can pause and resume this pass through. Now if the Thread is not stopped, the pass through continues even when I exit the application or the application looses focus (so even when the phone is on the desktop it keeps doing the passthrough).
#SuppressWarnings("deprecation")
#Override
public void onDestroy(){
newThread.stop();
}
This code causes the app to crash on exit (Why?) so I used
#Override
protected void onDestroy() {
android.os.Process.killProcess(android.os.Process.myPid());
// killProcess(android.os.Process.myPid());
}
that I found somewhere in stackoverflow (I forgot where). It seems to do what I want for now, but I want know if this is the proper way to stop the Thread or not. It does what I need, that is, it stops the passthrough when I exit the application, but I am not sure what exactly the killProcess() function does to my application overall, and if it is the best way to stop a Thread that I started myself.
Also, I can get the same effect if I exit my application (or loose focus to it) while the passthrough is being paused. But I assume this means the Thread is still running which means the infinite loop is also continuously running as well. Is it a good idea to do this, that is, just leave the Thread running, as long as my overall program is behaving as I want it to? What if I have lots of Threads or other background processes running? Can this practice cause memory problems in the future if the app grows too big?
Threads should periodically check for some shouldTerminate flag in their loop, then just set this flag from UI thread and (optionally) wait until thread terminate gracefully. Don't forget volatile or proper field synchronization.
Please remember to call super.onDestroy after releasing your memory or finishing the thread. Otherwise it will throw Exception:
#Override
protected void onDestroy() {
// You code here to finish the thread
super.onDestroy(); // Please call THIS too
}
Hope this helps.
Change your Thread class to something like this:
class MyThread extends Thread {
private volatile boolean finished = false;
#Override
public void run() {
while (!finished) {
// do stuff on thread
}
}
public void stopThread() {
finished = true;
}
}
In your onDestroy method call stopThread().
#Override
protected void onDestroy() {
newThread.stopThread();
super.onDestroy();
}
If you wish, you can also wait for thread to stop, by using this method:
private void joinThread(Thread thread) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// to be handled as you wish
}
}
}
Put this method in your activity and call it after newThread.stopThread().
There is already a provided flag for interuption.
Correct your while loop to the following.
And just call interupt(); in onDestroy or wherever.
private class thrd extends Thread {
#Override
public void run() {
super.run();
while (!isInterrupted()) {
//TODO
}
}
}
#Override
protected void onDestroy() {
super.onDestroy();
thrd.interupt();
}
Can someone explain to me 2 things about the thread code that I finally made almost working the way it should. I want to do a periodic task in the background every x seconds and be able to stop and start it at will. I coded that based on the examples I found, but I'm not sure if I made it in the right way. For the purpose of debugging, the task is displaying a time with custom showTime().
public class LoopExampleActivity extends Activity {
TextView Napis, Napis2;
Button button1,button_start,button_stop;
Handler handler = new Handler();
Boolean tread1_running = true;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Napis = (TextView) findViewById(R.id.textView1);
Napis2 = (TextView) findViewById(R.id.textView2);
button1 = (Button) findViewById(R.id.button1);
button_stop = (Button) findViewById(R.id.button_stop);
button_start = (Button) findViewById(R.id.button_start);
button_stop.setOnClickListener(new OnClickListener() {
#Override
public void onClick (View v) {
tread1_running = false;
}
});
button_start.setOnClickListener(new OnClickListener() {
#Override
public void onClick (View v) {
tread1_running = true;
}
});
thread.start();
}// endof onCreate
final Runnable r = new Runnable()
{
public void run()
{
handler.postDelayed(this, 1000);
showTime(Napis2);
}
};
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(tread1_running) {
sleep(1000);
handler.post(r);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
Now the questions are:
1)Will my thread quit forever if I stop it with the stop button?
2)Why can't I start it again with the start_button? If I add the tread.start() in a button, will it crash?
3) I tried a second version when I let the thread run and put a condition into the handler. The only way I can get it to work is to loop conditionaly in the handler by adding an
if (thread1_running) {
handler.postDelayed(this, 2000);
showTime(Napis2);
}
And changing the condition in a thread start to while (true) but then I have an open thread that is running all the time and I start and stop it in a handler, and it posts more and more handlers.
So, finally I get to the point it looks like that:
final Runnable r = new Runnable()
{
public void run()
{
if (thread1_running) handler.postDelayed(this, 1000);
showTime(Napis2);
}
};
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
if (thread1_running) handler.post(r);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Is the proper way to do that is to start and stop a whole thread? Or that is the best way?
The best way to achieve something like that would be, in my humble opinion, to postDelayed(Runnable, long).
You could do something like this. Class definition:
private Handler mMessageHandler = new Handler();
private Runnable mUpdaterRunnable = new Runnable() {
public void run() {
doStuff();
showTime(Napis2);
mMessageHandler.postDelayed(mUpdaterRunnable, 1000);
}
};
And control true run/stop like this:
To start:
mMessageHandler.postDelayed(mUpdaterRunnable, 1000);
And to stop:
mMessageHandler.removeCallbacks(mUpdaterRunnable);
It's much much simpler, in my humble opinion.
Threads a described by a state machine in java.
When a thread get outs of its run method, it enters in the stopped state and can't be restarted.
You should always stop a thread by getting it out of its run method as you do, it s the proper way to do it.
If you want to "restart the thread", start a new instance of your thread class.
You should better encapsulate your thread and its running field. It should be inside your thread class and the class should offer a public method to swich the boolean. No one cares about your datastructure, hide them. :)
You should consider using runOnUIThread for your runnable, its much easier to use than handlers.