I am developing an Android app and I am doing some heavy work (bringing data from an online web page and parsing it to store in database) in a service. Currently, it is taking about 20+ mins and for this time my UI is stuck. I was thinking of using a thread in service so my UI doesn't get stuck but it is giving error. I am using the following code:
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
Toast.makeText(getBaseContext(), "Running Thread...", Toast.LENGTH_LONG).show();
}
} catch (InterruptedException e) {
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
}
}
};
thread.start();
This simple code is giving run time error. Even If I take out the while loop, it is still not working.
Please, can any one tell me what mistake I am doing. Apparently, I copied this code directly from an e-book. It is suppose to work but its not.
Android commandment: thou shall not interact with UI objects from your own threads
Wrap your Toast Display into runOnUIThread(new Runnable() { });
Example of new thread creation taken from Android samples (android-8\SampleSyncAdapter\src\com\example\android\samplesync\client\NetworkUtilities.java):
public static Thread performOnBackgroundThread(final Runnable runnable) {
final Thread t = new Thread() {
#Override
public void run() {
try {
runnable.run();
} finally {
}
}
};
t.start();
return t;
}
runnable is the Runnable that contains your Network operations.
You can use HandlerThread and post to it, here is an example to service that has one.
public class NetworkService extends Service {
private HandlerThread mHandlerThread;
private Handler mHandler;
private final IBinder mBinder = new MyLocalBinder();
#Override
public void onCreate() {
super.onCreate();
mHandlerThread = new HandlerThread("LocalServiceThread");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
}
public void postRunnable(Runnable runnable) {
mHandler.post(runnable);
}
public class MyLocalBinder extends Binder {
public NetworkService getService() {
return NetworkService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
You may define your jobs in a runnable object, use a thread object for running it and start this thread in your service's onStartCommand() function. Here is my notes:
In your service class:
define your main loop in an Runnable object
create Thread object with the runnable object as parameter
In your service class's onStartCommand method():
call thread object's start function()
my code :
private Runnable busyLoop = new Runnable() {
public void run() {
int count = 1;
while(true) {
count ++;
try {
Thread.sleep(100);
} catch (Exception ex) {
;
}
ConvertService.running.sendNotification("busyLoop" + count);
}
}
};
public int onStartCommand(Intent intent, int flags, int startId) {
sendNotification("onStartCommand");
if (! t.isAlive()) {
t.start();
}
return START_STICKY;
}
Related
I want to load a url in the background after every 30 seconds (as a Service) in my app. I have to load url in my service class, as it has no layout, so webview is not suitable for this. What should I use to load url in background even when the app is closed ?
MyService.java class
public class MyService extends Service {
Activity activity ;
Handler handler = new Handler();
Runnable runnable;
int delay = 7*1000;
public MyService(Activity activity){
this.activity = activity ;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler.postDelayed( runnable = new Runnable() {
public void run() {
loadURL();
handler.postDelayed(runnable, delay);
}
}, delay);
return START_STICKY ;
}
#Override
public void onDestroy() {
}
public void loadURL(){
try{
String id = activity.getIntent().getStringExtra("ID");
URL url = new URL("http://localhost/att.php?id=" + id + "&status=&submit=Insert");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
} catch (Exception e){
Toast.makeText(this, ""+e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
You can use the new WorkManager.
Basically you create a Worker class that extends from one of these:
Worker
CoroutineWorker
RxWorker
ListenableWorker
Then you declare it like this:
val mWorker = PeriodicWorkRequestBuilder<Worker>(15, TimeUnit.MINUTES)
.addTag(WORK_TAG)
.setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
.build()
And then enqueue unique work so that work manager doesn't start more of the same task:
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(WORK_TAG, ExistingPeriodicWorkPolicy.KEEP, locationWorker)
Using your code when you extend your Worker class to for example ListenableWorker, you override a startWork() function and in the body run:
handler.postDelayed( runnable = new Runnable() {
public void run() {
loadURL();
handler.postDelayed(runnable, delay);
}
}, delay);
I'm currently trying to do an app that keeps track of the phone through the GPS by using a service. in order to get the GPS to update the coordinates, I need to use a handler within the service. Right now the proble I have is that when the I do the Handler.post, it gets stuck in an loop, and after that, it completely ignores the rest of the service code.
When I was debugging, I found out that the handler was alternating messages between methods but nothing useful came out of it, it was just a loop between the same methods over and over again.
Here's my Service code that includes the handler:
public int onStartCommand(Intent intent, int flags, int startId)
{
ctx = ServicioDeFondo.this;
mHandler = new Handler();
reportarGPS = new Thread(new Runnable() { public void run()
{
try
{
while(true)
{
mHandler.post(new Runnable() {
#Override
public void run() {
gps = new GPSTrack(ctx);
latitude = String.valueOf(gps.getLatitude());
longitude = String.valueOf(gps.getLongitude());
}
});
Thread.sleep(10000);
try {
new APISendClass().execute();
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
catch (Exception e)
{
//TODO Auto-generated catch block
e.printStackTrace();
}
} });
reportarGPS.start();
return START_STICKY;
}
I"ve been stuck here all day, any help would be greatly appreciated!
With your brief description of the problem, it's hard to understand what the expected behavior is. You don't explain what GPSTrack and APISendClass do and what type of objects that are. You state "it gets stuck in a loop". It's not clear what "it" is. With the while (true) statement, the thread will loop until cancelled.
Note that Service methods, such as onStartCommand() run on the main thread. That means that your Handler() constructor associates the handler with the main thread. The runnables you post to that handler run on the main thread. Is that what you wanted?
Also note that stopping the service by stopSelf() or Context.stopService() does not kill the thread. You need to have code to cancel the thread when it is no longer needed. This is often done in onDestroy().
I took the code you posted, replaced the calls to unknown objects with Log statements and ran it. The logcat output alternated between "Get lat/long" and "APISendClass()".
Handler mHandler;
Context ctx;
Thread reportGPS;
public int onStartCommand(Intent intent, int flags, int startId){
Log.i("TEST", "onStartCommand()");
ctx = this;
// Service methods run on main thread.
// Handler constructor with no args associates Handler
// with current thread, which here is the main thread.
mHandler = new Handler();
reportGPS = new Thread(new Runnable() {
#Override
public void run() {
try {
while (true) {
mHandler.post(new Runnable() {
#Override
public void run() {
// This runnable is posted to the main thread.
// Is that what you intended?
//gps = new GPSTrack(ctx);
//latitude = String.valueOf(gps.getLatitude());
//longitude = String.valueOf(gps.getLongitude());
Log.i("TEST", "Get lat/long");
}
});
Thread.sleep(2000);
try {
//new APISendClass().execute();
Log.i("TEST", "APISendClass().execute()");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
reportGPS.start();
return START_STICKY;
}
i want to start Asynchoronous task after some sleep time. For that i am using thread and i start my asynchronous task in that thread finally block. But it gives cant create a handler inside a thread exception.
i am using the following logic.
thread= new Thread()
{
public void run()
{
try
{
int waited = 0;
while (waited < 300)
{
sleep(100);
waited += 100;
}
}
catch (InterruptedException e)
{
// do nothing
}
finally
{
Load ld=new Load();
ld.execute();
}
}
};
thread.start();
Well, first of all, if the final goal is to run AsyncTask after some delay, I would use Handler.postDelayed instead of creating separate Thread and sleeping there:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
new Load().execute();
}
}, 300); //300ms timeout
But, if you really wanna make fun of Android, you can create HandlerThread - special thread which has looper in it, so your AsyncTask will not be complaining anymore:
thread= new HandlerThread("my_thread")
{
public void run()
{
try
{
int waited = 0;
while (waited < 300)
{
sleep(100);
waited += 100;
}
}
catch (InterruptedException e)
{
// do nothing
}
finally
{
Load ld=new Load();
ld.execute();
}
}
};
thread.start();
Please note that you are responsible for calling quit() on this thread. Also I'm not sure what happens if you quit this thread before AsyncTask is done. I don't remember where AsyncTask posts its results - to the main thread, or to the thread it was called from...
In any case, second option is just a mess, so don't do it:) Use the first one
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// Do whatever you want.
}
}, SPLASH_TIME_OUT);
}
You can use like above. there SPLASH_TIME_OUT is the millisecond value that u want to make a delay.
Use Handler class, and define Runnable YourAsyncTask that will contain code executed after sleepTime
mHandler.postDelayed(YourAsyncTask, sleepTime);
You must run AsyncTask in UI thread, so you can use something like this:
class YourThread extends Thread{
private Activity _activity;
public YourThread(Activity _activity){
this activity = _activity;}
public void run()
{
try
{
int waited = 0;
while (waited < 300)
{
sleep(100);
waited += 100;
}
}
catch (InterruptedException e)
{
// do nothing
}
finally
{
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Load ld=new Load();
ld.execute();
}
});
}
}
}
and in your activity call thread like this:
YourThread thread = new YourThread(this);
thread.start();
also note: use soft reference to activity or do not forget kill thred when activity will be destroyed.
just do your like below code:
define a thread globally.
public static Thread thread;
thread= new Thread() {
public void run() {
sleep(time);
Message msg = setTextHandler.obtainMessage(2);
setTextHandler.sendMessage(msg);
}
};
thread.start();
and your handler look like
private final Handler setTextHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (thread!= null) {
thread.interrupt();
thread= null;
}
switch (msg.what) {
case 2: //do your work here
Load ld=new Load();
ld.execute();
break;
}
}
};
I'm trying to download multiple files using IntentService. The IntentService donwloads them okey as expected one at a time, the only problem is that when the Internet is down the intent service will not stop the donwload rather it will get stuck on the current thread. If I manage to stop the current thread it will continue running the other threads stored in its queue even though the internet connection is down.
It was suggested in another post that I use LinkedBlockingQueue and create my own Worker thread that constantly checks this queue for new threads. Now I know there are some increased overheads and thus performance issues when creating and destroying threads but that's not a concern in my case.
At this point, All I want to do is understand how IntentService works which as of yet I don't (and I have looked at the code) and then come up with my own implementation for it using LinkedBlockingQueue controlled by a Worker thread. Has anyone done this before ? Could provide a working example, if you feel uncomfortable providing the source code, pseudo code is fine by me. Thanks!
UPDATE: I eventually implemented my own Intent Service using a thread that has a looper which checks the queue which in turn stores the intents passed from the startService(intent).
public class MyIntentService extends Service {
private BlockingQueue<Download> queue = new LinkedBlockingQueue<Download>();
public MyIntentService(){
super();
}
#Override
public void onCreate() {
super.onCreate();
new Thread(queueController).start();
Log.e("onCreate","onCreate is running again");
}
boolean killed = false;
Runnable queueController = new Runnable() {
public void run() {
while (true) {
try {
Download d =queue.take();
if (killed) {
break;
}
else {
d.downloadFile();
Log.e("QueueInfo","queue size: " + queue.size());
}
}
catch (InterruptedException e) {
break;
}
}
Log.e("queueController", "queueController has finished processing");
Log.e("QueueInfo","queue size: " + queue.toString());
}
};
class Download {
String name;
//Download files process
void downloadFile() {
//Download code here
}
Log.e("Download","Download being processed is: " + name);
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
}
public void killService(){
killed = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Download d = new Download();
d.setName(intent.getStringExtra("VIDEOS"));
queue.add(d);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.e("stopSelf","stopSelf has been just called to stop the Service");
stopSelf();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I'm not so sure about the START_NOT_STICKY in the onStartCommand() method. If it's the right flag to return or not. Any clarification on that would be appreciated!
UPDATE: I eventually implemented my own Intent Service using a thread that has a looper which checks the queue which in turn stores the intents passed from the startService(intent).
public class MyIntentService extends Service {
private BlockingQueue<Download> queue = new LinkedBlockingQueue<Download>();
public MyIntentService(){
super();
}
#Override
public void onCreate() {
super.onCreate();
new Thread(queueController).start();
Log.e("onCreate","onCreate is running again");
}
boolean killed = false;
Runnable queueController = new Runnable() {
public void run() {
while (true) {
try {
Download d =queue.take();
if (killed) {
break;
}
else {
d.downloadFile();
Log.e("QueueInfo","queue size: " + queue.size());
}
}
catch (InterruptedException e) {
break;
}
}
Log.e("queueController", "queueController has finished processing");
Log.e("QueueInfo","queue size: " + queue.toString());
}
};
class Download {
String name;
//Download files process
void downloadFile() {
//Download code here
}
Log.e("Download","Download being processed is: " + name);
}
public void setName(String n){
name = n;
}
I have a very simple UI and i need to constantly run a check process, so I am trying to use a Thread with a while loop.
When I run the loop with nothing but a Thread.sleep(1000) command, it works fine, but as soon as I put in a display.setText(), the program runs for a second on the emulator then quits. I cannot even see the error message since it exits so fast.
I then took the display.setText() command outside the thread and just put it directly inside onCreate, and it works fine (so there is no problem with the actual command).
here is my code, and help will be greatly appreciated.
Thank you!
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
on=(Button) findViewById(R.id.bon);
off=(Button) findViewById(R.id.boff);
display=(TextView) findViewById(R.id.tvdisplay);
display2=(TextView) findViewById(R.id.tvdisplay2);
display3=(TextView) findViewById(R.id.tvdisplay3);
stopper=(Button) findViewById(R.id.stops);
stopper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(boo=true)
{
boo=false;
display3.setText("System Off");
}
else{
boo=true;
}
}
});
Thread x = new Thread() {
public void run() {
while (boo) {
display3.setText("System On");
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
display3.setText("System On");
display3.setText("System On");
x.start();
}
You can't update the UI from a non-UI thread. Use a Handler. Something like this could work:
// inside onCreate:
final Handler handler = new Handler();
final Runnable updater = new Runnable() {
public void run() {
display3.setText("System On");
}
};
Thread x = new Thread() {
public void run() {
while (boo) {
handler.invokeLater(updater);
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
You could also avoid a Handler for this simple case and just use
while (boo) {
runOnUiThread(updater);
// ...
Alternatively, you could use an AsyncTask instead of your own Thread class and override the onProgressUpdate method.
Not 100% certain, but I think it is a case of not being able to modify UI controls from a thread that did not create them?
When you are not in your UI thread, instead of display3.setText("test") use:
display3.post(new Runnable() {
public void run() {
display3.setText("test");
{
});
You should encapsulate this code in an AsyncTask instead. Like so:
private class MyTask extends AsyncTask<Void, Void, Void> {
private Activity activity;
MyTask(Activity activity){
this.activity = activity;
}
protected Long doInBackground() {
while (true){
activity.runOnUiThread(new Runnable(){
public void run(){
display3.setText("System On");
}
});
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
Then just launch the task from your onCreate method.
In non-UI thread,you can't update UI.In new Thread,you can use some methods to notice to update UI.
use Handler
use AsyncTask
use LocalBroadcast
if the process is the observer pattern,can use RxJava