i'm writing simple android service and i want to use such as Toast or Notification but i get this error:
FATAL EXCEPTION: Thread-17116
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
i can not use runOnUiThread . my service does not know that. for example i try to use that with : this, getBaseContect(), getApplication, mContext for .runOnUiThread(new Runnable() {}
i get problem and i can not resolve problem.
this is my code:
public class TsmsService extends Service {
private Timer smsThread;
private DatabaseHandler db;
private SQLiteDatabase dbHelper;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
smsThread = new Timer();
GetSMSThread getSMSThread = new GetSMSThread(getBaseContext());
smsThread.scheduleAtFixedRate(getSMSThread, 0, 1000); //(timertask,delay,period)
return super.onStartCommand(intent, flags, startId);
}
public class GetSMSThread extends TimerTask {
private Context mContext;
public GetSMSThread(Context context) {
mContext = context;
}
#Override
public void run() {
this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplication() , "Service is Running ... " , Toast.LENGTH_SHORT).show();
}
});
}
}
}
Try creating a Handler in onStartCommand (so, from the UI thread). Then use that Handler to trigger the Toast. For example:
private Handler mToastHandler = null;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
...
mToastHandler = new Handler();
...
}
...
// from inside your child thread
mToastHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(...);
}
});
Here you can use ResultReceiver that is used for the purpose of receiving a callback result from someone. In your case its Service
You can check the complete example of Service with TimerTask using ResultReceiver for updating the UI inside Activity
Related
I successfully used a service to do a certain task in the foreground. Now, to do it in the background, I'd remove the handler.removeCallbacks method in onDestroy().
But this would also prevents me from stopping the service using stopService(intent).
I saw on the official docs that I should maybe use JobScheduler (as I target API 28).
Here is a more precise indication of my code :
public class MainActivity {
private Intent intent;
onCreate() {
if (intent == null) {
intent = new Intent(this, MyService.class);
}
}
startService(intent);
... // Then is some code to stop the service if needed with stopService(intent)
}
--------------------------------------------------------------
public class myService {
private Handler handler = null;
private static Runnable runnable = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
handler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
System.out.println("Running service times " + i);
i++;
handler.postDelayed(runnable, 1000);
}
};
handler.post(runnable);
}
#Override
public void onDestroy() {
handler.removeCallbacks(runnable);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
I would like it to run in the background (even if the device is locked) but still being able to disable the service (or JobScheduler?).
What are your suggestions?
you can use work manager
or job dispatcher
and there is a lot of options like
SyncAdapter, Bound services, Intent Service
you can use one of these options according to your need
I have tried to make a service to recognize the user's current activity.
But this code crashes everytime.
It throws exception:
java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.android.gms.location.DetectedActivity com.google.android.gms.location.ActivityRecognitionResult.getMostProbableActivity()' on a null object reference
at com.always_in_beta.ecodrive.service.UserTrackService.detectActivity(UserTrackService.java:51)
at com.always_in_beta.ecodrive.service.UserTrackService$1.run(UserTrackService.java:27)
The code is:
public class UserTrackService extends Service {
public Handler handler = null;
public Runnable runnable = null;
int count = 0;
public Context context = this;
public Intent intentt;
#Override
public void onCreate() {
handler = new Handler();
runnable = new Runnable() {
public void run() {
detectActivity();
}
};
handler.postDelayed(runnable, 4000);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
Toast.makeText(context, "Service stopped", Toast.LENGTH_LONG).show();
}
#Override
public IBinder onBind(Intent intent) {
intentt = intent;
return null;
}
public void detectActivity() {
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intentt);
DetectedActivity activity = result.getMostProbableActivity();
Toast.makeText(context, activity.toString(), Toast.LENGTH_SHORT).show();
Log.d("tag_tag_tag", activity.toString());
}
}
ActivityRecognitionResult#extractResult(android.content.Intent)
Returns
an ActivityRecognitionResult, or null if the intent doesn't
contain an ActivityRecognitionResult.
So, according to your null pointer stacktrace, that's expected because you can't run getMostProbableActivity() on a null.
I've declared a Service class:
public class MyService extends Service{
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Parsing().execute();
return Service.START_STICKY;
}
private class Parsing extends AsyncTask<Void, Void, Void> {
List<MyObject> myList = null;
MyAdapter adapter = null;
#Override
protected void onPreExecute() {
super.onPreExecute();
myList = new ArrayList<MyObject>();
}
#Override
protected Void doInBackground(Void... params) {
while (downloadDataFromInternet)
myList.add(new MyObject(par1, par2, par3, par4));
}
#Override
protected void onPostExecute(Void result) {
if (myList.size() > 0)
adapter = new MyAdapter(this, myList);
}
}
}
Now I would like to execute this service every 10 minutes (for example) also when activity is in background, but I want that when activity come back to foreground, listView of MyFragment uses the adapter declared in the service.
Can you please help me? I have no idea about how to do this.
If you have to exactly execute the service in 10 minutes of interval .
You can use thread scheduler as :
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//schedule a thread
scheduler.schedule(new Runnable() {
public void run() {
startservice();
}
}, 10, TimeUnit.MINUTES);
return Service.START_STICKY;
}
private startService(){
// you background service related work
while (downloadDataFromInternet)
myList.add(new MyObject(par1, par2, par3, par4));
// schedule a new thread
scheduler.schedule(new Runnable() {
public void run() {
startservice();
}
}, 10, TimeUnit.MINUTES);
}
My suggestion use database:
Once this Background task runs then update your data into database. Once you open your UI then you can read value from database and you can also update UI.
Sounds like you want to communicate between the Service and the Activity. While service is like independent from a specific context, activity isn't.
Therefore Service cannot (should not) talk to the activity directly, especially if the activity is killed/re-created.
What you should do is develop a method of intercommunicating by using a database or SharedPreferences, to store your data from within the service. Then, the activity would fetch this data and use it.
You can use Timer Task to execute some task after a specific time period
1 You need to create Subclass of TimerTask
eg
class Mytask extends Timertask{
#Override
public void run() {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
//your code you want to run in UI thread
});
}
}
2 Start this task from your service
Timer timer = new Timer();
MyTask task= new MyTask(getApplicationContext());
timer.scheduleAtFixedRate(task,1,1000*60*10); // for 10 min
Hope this is what you want
I initialize new Thread in service but when i start service the new one is made and it make my app crash beacause I use camera in it.
How to make that it will be ony one instance of that Thread?
When Thread is closing? If I close service where I made it, it will be also closed?
you could use a lock or a static variable:
private static boolean isThreadRunning;
and then in your service:
if(isThreadRunning)
return;
Thread t=new Thread(new Runnable(){
protected void run(){
isThreadRunning=true;
while(yourcondition){
//your thread code...
}
isThreadRunning=false;
//if you want to start another thread after this one is ended, you should post a message to a handler here and it should start another thread like this
}
});
You can also achieve this using Handler class, which is recommended by Google in thread operations. The code bellow shows generic example how to use it in Service.
public class MyService extends Service{
private final Handler handler = new Handler();
private final static int RUNABLE_WHAT=6558057;
private final static int PEROID=6*1000;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(!handler.hasMessages(RUNABLE_WHAT))
{
handler.sendMessageDelayed(new Worker().extractMessage(), PEROID);
}
return START_STICKY;
}
private class Worker implements Runnable{
#Override
public void run() {
//DO WORK HERE
handler.sendMessageDelayed(new Worker().extractMessage(), PEROID);
}
private Message extractMessage()
{
Message message = Message.obtain(handler, this);
message.what=RUNABLE_WHAT;
return message;
}
}
}
I'm trying to download some data of a url every X minutes. This is run from a Service.
I have the following in my Service class:
public class CommandsService extends Service {
public String errormgs;
// in miliseconds
static final long DELAY = 60*1000;
public Timer timer;
public int onStartCommand (Intent intent, int flags, int startId) {
TimerTask task= new TimerTask (){
public void run(){
//do what you needs.
processRemoteFile();
// schedule new timer
// following line gives error
timer.schedule(this, DELAY);
}
};
timer = new Timer();
timer.schedule(task, 0);
return START_STICKY;
}
//....
}
Runs fine a first time, but when I try to "schedule" the timer a second time with the DELAY, LogCat complains:
"TimeTask scheduled already"
How could I re-schedule the Timer?
The TimerTask is a single use item. It can't be rescheduled or reused; you'll need to create new instances on the fly as you need them.
How about:
public class CommandsService extends Service {
public String errormgs;
// in miliseconds
static final long DELAY = 60*1000;
public Thread thread;
public int onStartCommand (Intent intent, int flags, int startId) {
Runnable runnable = new Runnable () {
public void run() {
while (<condition>) {
//do what you needs.
processRemoteFile();
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
}
}
}
};
thread = new Thread(runnable);
thread.start();
return START_STICKY;
}
//...
}