I have this code:
package org.example.Threading;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ThreadingActivity extends Activity implements OnClickListener {
/** Called when the activity is first created. */
private doinback background = new doinback();
Handler handle= new Handler(){
#Override
public void handleMessage(Message msg) {
Log.e("INSIDE HANDLER", "About to stop the thread.");
background.stopThread();
}};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.e("ONCREATE", "BEFORE Thread");
background.start();
Log.e("ONCREATE", "AFTER Thread started");
View button = (Button)findViewById(R.id.button1);
button.setOnClickListener(this);
}
class doinback extends Thread{
private volatile boolean isRunning = false;
public void run() {
while(isRunning){
Log.e("INSIDE THREAD", "about to sleep");
handle.sendMessage(handle.obtainMessage());
}
}
public void stopThread()
{
isRunning = false;
}
public void startThread(){
Log.e("INSIDE StartThread","MAKING isRunning True");
isRunning = true;
}
}
public void onClick(View v) {
background.startThread();
Log.e("INSIDE ONCLICK", "made isRunning true, about to leave");
}
}
I am trying to understand why it does not go back to the thread and if there is something I am doing wrong and if so what is the best way to go back and forth from a thread, for instance with the stopThread() function I change the value of the while variable to stop the thread from running. When I run the code and press the button it does not start the thread. Any ideas why?
When background.start() is called, isRunning is still false, so the thread is started(but didn't enter the while loop) and stopped immediately.
To ensure the thread to enter the while loop when startThread is called, you can put the following code in the startThread() method:
public void startThread(){
isRunning = true;
start();
}
And you don't call background.start() in onCreate(), just remove that line.
EDIT
If you want to keep a single thread alive, so you can "start" it and "stop" it as many times as you like, you can use the following code:
public void run () {
while (isRunning) {
if(!isWorking) {
try { Thread.sleep(10); } catch (InterruptedException ex) { }
continue;
}
//.. do your work here.
}
}
You control the running state of the thread with isRunning, and the working state with isWorking.
Related
As part of my learning Android Threading, I have done the below code.
package simple.learning.com.samplethread;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
MyThread myThread;
Button button;
private static class MyThread extends Thread {
public Handler mHandler;
public void run () {
Log.d ("TESTME", " iNSIDE RUN..");
Looper.prepare();
mHandler = new Handler () {
public void HandleMessage (Message msg) {
Log.d("TESTME", "iNSIDE HandleMessage");
if ( msg.what == 0) {
someWork();
}
}
};
Looper.loop();
}
public void someWork()
{
while (true) {
Log.d("TESTME", "Inside someWork ");
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myThread = new MyThread();
myThread.start();
Button btn = (Button) findViewById(R.id.button1);
assert btn != null;
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (myThread.mHandler != null) {
Log.d("TESTME", " bUTTON pRESSED..");
Message msg = myThread.mHandler.obtainMessage(0);
myThread.mHandler.sendMessage(msg);
}
}
});
}
}
When I Click the button, I expect the msg to be posted into the message queue. But, I don't see any output displayed. Any help would be appreciated.
You made a small mistake in overriding the handleMessage, instead of overriding the real one you added some method. Below is the working solution:
private static class MyThread extends Thread {
public Handler mHandler;
public void run() {
Log.d("TESTME", " iNSIDE RUN..");
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.d("TESTME", "iNSIDE HandleMessage");
if (msg.what == 0) {
someWork();
}
}
};
Looper.loop();
}
public void someWork() {
while (true) {
Log.d("TESTME", "Inside someWork ");
}
}
}
I am testing surfaceView, basically the app jsut changes the color of the background.
The app starts with no issue but when I "pause" the activity and "resume" it, the app is blocked in the "pause()" method loop.
this is my code:
import java.util.Random;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class SurfaceViewTest extends Activity {
FastRenderView renderView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_surface_view_test);
renderView= new FastRenderView(this);
setContentView(renderView);
}
protected void onResume() {
super.onResume();
renderView.resume();
}
#Override
protected void onPause() {
super.onPause();
renderView.pause();
}
public class FastRenderView extends SurfaceView implements Runnable {
Thread renderThread=null;
SurfaceHolder holder;
volatile boolean running=false;
Random rand= new Random(); //random number creator----
public FastRenderView(Context context) {
super(context);
holder=getHolder(); //<<-check the this statement
}
public void resume() {
Log.d("ZR", "in resume");
running=true;
renderThread=new Thread(this);
renderThread.start(); //<<<--AVVIA IL THREAD
}
#Override
public void run() {
Log.d("ZR", "in running");
while(running){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(!holder.getSurface().isValid())
continue;
Canvas canvas = holder.lockCanvas();
canvas.drawRGB(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255));
holder.unlockCanvasAndPost(canvas);
}
}
public void pause() {
running = false;
Log.d("ZR", "in pause");
while(true){ //<<<<<<<<<<<<<<CHECKKKKKK
try {
renderThread.join();
Log.d("ZR", "in pause end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
The while(true) loop without a break in it will never stop in method pause(). I would expect something like a return after succesfully joined the rendering thread (waited till it ended)
With your volatile declaration of running the while-loop in run() should be ok.
I am trying to implement a service in Android that displays a toast message every 1 minute in Android. I am new to Android development and learned about AlarmManager that will help me do this. I have implemented the code in the following way:
This is my IIManagerActivity class
package com.example.iimanager;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.Menu;
import android.widget.Toast;
public class IIManagerActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_iimanager);
AlarmManager mgr=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent i=new Intent(this, SampleService.class);
PendingIntent pi=PendingIntent.getService(this, 0, i, 0);
mgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), AlarmManager.INTERVAL_FIFTEEN_MINUTES/900, pi);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_iimanager, menu);
return true;
}
}
And this is my SampleService that is meant to display a toast message.
For some reason I cannot get to see a toast message no matter how long I wait.
package com.example.iimanager;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class SampleService extends IntentService {
public SampleService() {
super("SimpleService");
//Toast.makeText(getApplicationContext(), "this is my Toast message!!! =)", Toast.LENGTH_LONG).show();
}
#Override
protected void onHandleIntent(Intent intent) {
//do something
Toast.makeText(getApplicationContext(), "this is my Toast message!!! =)", Toast.LENGTH_LONG).show();
}
}
Can you please tell me what's wrong and what needs to be done to get it corrected?
Thank you very much in advance.
Copy the below 3 lines for toast call
Timer timer = new Timer();
TimerTask updateProfile = new SampleService(SampleService.this);
timer.scheduleAtFixedRate(updateProfile, 10,1000);
class CustomTimerTask extends TimerTask {
private Context context;
private Handler mHandler = new Handler();
// Write Custom Constructor to pass Context
public CustomTimerTask(Context con) {
this.context = con;
}
#Override
public void run() {
new Thread(new Runnable() {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "this is my Toast message!!! =)", Toast.LENGTH_LONG).show();
}
});
}
}).start();
}
}
Try following code,
MainActivity.java
public class MyService extends Service {
public static final long INTERVAL=60000;//variable for execute services every 1 minute
private Handler mHandler=new Handler(); // run on another Thread to avoid crash
private Timer mTimer=null; // timer handling
#Nullable
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("unsupported Operation");
}
#Override
public void onCreate() {
// cancel if service is already existed
if(mTimer!=null)
mTimer.cancel();
else
mTimer=new Timer(); // recreate new timer
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(),0,INTERVAL);// schedule task
}
#Override
public void onDestroy() {
Toast.makeText(this, "In Destroy", Toast.LENGTH_SHORT).show();//display toast when method called
mTimer.cancel();//cancel the timer
}
//inner class of TimeDisplayTimerTask
private class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
// display toast at every 1 minute
Toast.makeText(getApplicationContext(), "Notify", Toast.LENGTH_SHORT).show();
}
});
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//load the layout file
startService(new Intent(this,MyService.class));//use to start the services
}
}
Also add this code in your manifest file
AndroidManifest.xml
<service android:name=".MyService"
android:enabled="true"/>
Try to create a Timer object.Then use the scheduleAtFixedRate(TimerTask) to repeat the Toast message.
You can just make a looping thread which contains your code.
Like this:
public class Toaster extends Thread{
public void run(){
//Your code to loop
thread.sleep(60000)
}
}
Hope it helps!
The following code is for a splash screen in my app.What I need to be done is when the activity loads the image should be displayed as default and then after few seconds the image should be changed to another in the same activity. I have another image like the first one with different color. I wanted to change the screen for that image after few seconds.
I have done it like this in my code.
package com.ruchira.busguru;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class SplashScreen extends Activity {
ImageView imgBus;
MediaPlayer introSound, bellSound;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen);
imgBus = (ImageView) findViewById(R.id.imgBus);
imgBus.setImageResource(R.drawable.blackbus);
introSound = MediaPlayer.create(SplashScreen.this, R.raw.enginestart);
introSound.start();
Thread timer = new Thread(){
public void run(){
try{
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
imgBus.setImageResource(R.drawable.bluekbus);
}
}
};
timer.start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.splash_screen, menu);
return true;
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
introSound.stop();
finish();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
introSound.stop();
finish();
}
}
but the problem is the program stops by executing in the thread saying...
"android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
How I can achieve this target ? Does anybody please help me to sort out this problem. I am new to android development..
Thanks.
You should use the ImageView's Handler and a Runnable. Handler's are schedulers specific to Android and they can run on the UI thread. Try this:
ImageView imgBus;
MediaPlayer introSound, bellSound;
Runnable swapImage = new Runnable() {
#Override
public void run() {
imgBus.setImageResource(R.drawable.bluekbus);
}
};
And inside onCreate() call:
imgBus = (ImageView) findViewById(R.id.imgBus);
imgBus.setImageResource(R.drawable.blackbus);
imgBus.postDelayed(swapImage, 3000); // Add me!
Understand that splash screens are frowned upon because you should focus on starting the app as soon as possible (while loading the slower element in the background). However sometimes a slight delay is unavoidable.
Write this inside finally
runOnUiThread(new Runnable() {
public void run() {
SplashScreen.class.img.setImageResource(R.drawable.bluekbus);
}
});
You should always update your UI from the UI Thread itself...
Try the following,
We cannot access and update the UI from worker threads, only we can access the UI from UIThread. If we need it to update with background thread then we can use Handler to do this like in the following code.
this.imgBus = (ImageView) findViewById(R.id.splashImageView);
imgBus.setImageResource(R.drawable.your_first_image);
this.handler = new Handler();
introSound = MediaPlayer.create(SplashTestForSO.this, R.raw.enginestart);
introSound.start();
Thread timer = new Thread(){
public void run(){
try{
sleep(2000);
YourActivity.this.handler.post(runnable);
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
}
}
};
timer.start();
this.runnable = new Runnable() {
public void run() {
//call the activity method that updates the UI
YourActivity.this.imgBus.setImageResource(R.drawable.your_scond_image_view);
}
};
I want to display toast message inside timer and I used the following code :
timer.scheduleAtFixedRate( new TimerTask()
{
public void run()
{
try {
fun1();
} catch (Exception e) {e.printStackTrace(); }
}
}, 0,60000);
public void fun1()
{
//want to display toast
}
And I am getting following error:
WARN/System.err(593): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
WARN/System.err(593): at android.os.Handler.(Handler.java:121)
WARN/System.err(593): at android.widget.Toast.(Toast.java:68)
WARN/System.err(593): at android.widget.Toast.makeText(Toast.java:231)
Thanks.
You can't make UI updates inside separate Thread, like Timer. You should use Handler object for UI update:
timer.scheduleAtFixedRate( new TimerTask() {
private Handler updateUI = new Handler(){
#Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
fun1();
}
};
public void run() {
try {
updateUI.sendEmptyMessage(0);
} catch (Exception e) {e.printStackTrace(); }
}
}, 0,60000);
The easiest way (IMO) is:
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
final String message = "Hi";
MyActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MyActivity.this, message, Toast.LENGTH_SHORT).show();
}
});
}
});
The key being MyActivity.this.runOnUiThread(Runnable).
create a Handler and display toast in this
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
// Toast here
}
};
You need access to the Context of the application to be able to do this. Try creating your own class which takes the context as input parameter:
private class MyTimerTask extends TimerTask {
private Context context;
public MyTimerTask(Context context) {
this.context = context;
}
#Override
public void run() {
Toast.makeText(context, "Toast text", Toast.LENGTH_SHORT).show();
}
}
Then in your timer:
timer.scheduleAtFixedRate( new MyTimerTask(this), 0,60000);
I wanted to make a simple project that could display a Toast in a Timer.
The Timer would be started using a service. Then, the Timer starts when the service is started and stops when service is stopped.
Class 1
package com.example.connect;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
Button button1,button2;
private Handler mHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1=(Button)findViewById(R.id.button1);
button2=(Button)findViewById(R.id.button2);
}
public void Start(View v)
{
startService(new Intent(MainActivity.this , Connect_service.class));
}
public void Stop(View v)
{
stopService(new Intent(MainActivity.this , Connect_service.class));
}
}
Class 2
package com.example.connect;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
public class Connect_service extends Service{
Timer timer = new Timer();
TimerTask updateProfile = new CustomTimerTask(Connect_service.this);
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
timer.scheduleAtFixedRate(updateProfile, 0, 5000);
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Toast.makeText(this, "Service Stopped", Toast.LENGTH_SHORT).show();
timer.cancel();
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
Class 3
package com.example.connect;
import java.util.TimerTask;
import android.content.Context;
import android.os.Handler;
import android.widget.Toast;
public class CustomTimerTask extends TimerTask {
private Context context;
private Handler mHandler = new Handler();
public CustomTimerTask(Context con) {
this.context = con;
}
#Override
public void run() {
new Thread(new Runnable() {
public void run() {
mHandler.post(new Runnable() {
public void run() {
Toast.makeText(context, "In Timer", Toast.LENGTH_SHORT).show();
}
});
}
}).start();
}
}
I'm trying to make my own toast with my own views.
I've successfully combined your approaches. The following code allows me to show toasts and change/remove views without crashing, just change the parameters of the MyTimerTask constructor to whatever you need to work on.
public void yourFunction(){
Timer timer = new Timer();
MyTimerTask mtc = new MyTimerTask(this.getContext(), tvNotice);
timer.schedule(mtc, 1000);
}
private class MyTimerTask extends TimerTask {
private TextView tv;
private Context context;
public MyTimerTask(Context pContext, TextView pTv) {
this.tv = pTv;
this.context = pContext;
}
#Override
public void run() {
updateUI.sendEmptyMessage(0);
}
private Handler updateUI = new Handler(){
#Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
tv.setText("TextView Message");
Toast.makeText(context, "Toast Message", 0).show();
}
};
}
You have to call UIThread for showing Toast, not from timer thread.
Else call UI thread from that timer thread.
This link will help you,
http://developer.android.com/resources/articles/timed-ui-updates.html
and this
http://developer.android.com/guide/appendix/faq/commontasks.html#threading