Hi I am trying to use the service class for first time and have been facing problems. What I want is an infinitely running (unless killed by Android System) service with an active Network connection. I have written the code which works fine on Android 4.3 and 4.4 but the application crashes when I try running on Android 2.2. My code is as follows:
public class BackgroundMusicService extends Service {
private MediaPlayer mp;
private int id;
private static class BackgroundAsyncTaskClass extends AsyncTask<Void, Void, Void>{
protected Void doInBackground(Void... params) {
Log.v("Async","Async Called");
/*Network connection will be created here*/
return null;
}
}
private class ForThread implements Runnable{
public void run() {
while (true) {
try {
Log.v("ThreadSleeping","5 sec");
BackgroundAsyncTaskClass task = new BackgroundAsyncTaskClass();
task.execute();
Thread.sleep(5000);
} catch (InterruptedException e) {
}finally{
Log.v("Finally called","Finally called");
}
}
}
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("onStartCommand Called","onStart Command Called");
Thread t;
ForThread ft = new ForThread();
t = new Thread(ft);
t.start();
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
if(null != mp){
mp.stop();
mp.release();
Log.v("Destroyed","onDestroy Called");
}
}
public void onTaskRemoved(Intent rootIntent) {
Intent restartServiceIntent = new Intent(getApplicationContext(),
this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(
getApplicationContext(), 1, restartServiceIntent,
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext()
.getSystemService(Context.ALARM_SERVICE);
alarmService.set(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
}
and the exception thrown by Android 2.2 is as follows:
04-28 09:51:41.435: W/dalvikvm(280): threadid=7: thread exiting with uncaught exception (group=0x4001d800)
04-28 09:51:41.435: E/AndroidRuntime(280): FATAL EXCEPTION: Thread-8
04-28 09:51:41.435: E/AndroidRuntime(280): java.lang.ExceptionInInitializerError
04-28 09:51:41.435: E/AndroidRuntime(280): at com.example.backgroundservicedemo.BackgroundMusicService$ForThread.run(BackgroundMusicService.java:45)
04-28 09:51:41.435: E/AndroidRuntime(280): at java.lang.Thread.run(Thread.java:1096)
04-28 09:51:41.435: E/AndroidRuntime(280): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
04-28 09:51:41.435: E/AndroidRuntime(280): at android.os.Handler.<init>(Handler.java:121)
04-28 09:51:41.435: E/AndroidRuntime(280): at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
04-28 09:51:41.435: E/AndroidRuntime(280): at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
04-28 09:51:41.435: E/AndroidRuntime(280): at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
Also, when I try using handler.post(new Runnable(){.... run(){}....} The UI hangs up but the background thread continues running and exits after it becomes out of memory.
Another thing that I have doubts about is:
When the application restarts, I want this active Service to stop, but how do I get a reference to this thread running in Background and how do I stop this? I would appreciate if anyone can redirect me to a suitable link/reference or could help me out with the code. Thanks
You have this inside a thread's run method
BackgroundAsyncTaskClass task = new BackgroundAsyncTaskClass();
task.execute();
Threading rules from the docs
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Related
I have a problem with AsyncTask in my app. AsyncTask is located in SplashScreenAcivity.java. It downloads data using json for MainActivity.java while showing splash screen. When data is loaded, app shows MainActivity screen. However, when i turn off internet connection app crashes. Instead of it i would like to move to MainActivity.java and show toast that internet connection must be turned on. SplashScreen.java loads data for listView in MainActivity.
SplashActivityScreen.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
new DownloadData().execute();
}
private class DownloadData extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
SyncHttpClient clientOne = new SyncHttpClient();
clientOne.get("https://api.themoviedb.org/3/tv/top_rated?api_key=d253f520df9cd868af7db8daaa0db8fb&language=en-US", new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
try {
tvseries0 = response.getJSONArray("results").getJSONObject(0).getString("name");
tvseries1 = response.getJSONArray("results").getJSONObject(1).getString("name");
tvseries2 = response.getJSONArray("results").getJSONObject(2).getString("name");
tvseries3 = response.getJSONArray("results").getJSONObject(3).getString("name");
tvseries4 = response.getJSONArray("results").getJSONObject(4).getString("name");
tvseries5 = response.getJSONArray("results").getJSONObject(5).getString("name");
tvseries6 = response.getJSONArray("results").getJSONObject(6).getString("name");
tvseries7 = response.getJSONArray("results").getJSONObject(7).getString("name");
tvseries8 = response.getJSONArray("results").getJSONObject(8).getString("name");
tvseries9 = response.getJSONArray("results").getJSONObject(9).getString("name");
tvseries10 = response.getJSONArray("results").getJSONObject(10).getString("name");
tvseries11 = response.getJSONArray("results").getJSONObject(11).getString("name");
tvseries12 = response.getJSONArray("results").getJSONObject(12).getString("name");
tvseries13 = response.getJSONArray("results").getJSONObject(13).getString("name");
tvseries14 = response.getJSONArray("results").getJSONObject(14).getString("name");
tvseries15 = response.getJSONArray("results").getJSONObject(15).getString("name");
tvseries16 = response.getJSONArray("results").getJSONObject(16).getString("name");
tvseries17 = response.getJSONArray("results").getJSONObject(17).getString("name");
tvseries18 = response.getJSONArray("results").getJSONObject(18).getString("name");
tvseries19 = response.getJSONArray("results").getJSONObject(19).getString("name");
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(int statusCode, Header[] headers,Throwable e , JSONObject response) {
Toast.makeText(SplashScreenActivity.this, "Turn on the internet and swipe to refresh.", Toast.LENGTH_SHORT).show();
}
});
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Intent i = new Intent(getApplicationContext(), MainActivity.class);
i.putExtra("tvseries0", tvseries0);
i.putExtra("tvseries1", tvseries1);
i.putExtra("tvseries2", tvseries2);
i.putExtra("tvseries3", tvseries3);
i.putExtra("tvseries4", tvseries4);
i.putExtra("tvseries5", tvseries5);
i.putExtra("tvseries6", tvseries6);
i.putExtra("tvseries7", tvseries7);
i.putExtra("tvseries8", tvseries8);
i.putExtra("tvseries9", tvseries9);
i.putExtra("tvseries10", tvseries10);
i.putExtra("tvseries11", tvseries11);
i.putExtra("tvseries12", tvseries12);
i.putExtra("tvseries13", tvseries13);
i.putExtra("tvseries14", tvseries14);
i.putExtra("tvseries15", tvseries15);
i.putExtra("tvseries16", tvseries16);
i.putExtra("tvseries17", tvseries17);
i.putExtra("tvseries18", tvseries18);
i.putExtra("tvseries19", tvseries19);
startActivity(i);
finish();
}
}
}
Crash 1
04-30 13:15:35.165 12349-12365/przemo.me.recommend.recommendme E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: przemo.me.recommend.recommendme, PID: 12349
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:318)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at com.loopj.android.http.AsyncHttpResponseHandler.onUserException(AsyncHttpResponseHandler.java:304)
at com.loopj.android.http.AsyncHttpResponseHandler.handleMessage(AsyncHttpResponseHandler.java:395)
at com.loopj.android.http.AsyncHttpResponseHandler.sendMessage(AsyncHttpResponseHandler.java:401)
at com.loopj.android.http.AsyncHttpResponseHandler.sendFailureMessage(AsyncHttpResponseHandler.java:319)
at com.loopj.android.http.AsyncHttpRequest.run(AsyncHttpRequest.java:109)
at com.loopj.android.http.SyncHttpClient.sendRequest(SyncHttpClient.java:95)
at com.loopj.android.http.AsyncHttpClient.get(AsyncHttpClient.java:1078)
at com.loopj.android.http.AsyncHttpClient.get(AsyncHttpClient.java:1037)
at przemo.me.recommend.recommendme.SplashScreenActivity$DownloadData.doInBackground(SplashScreenActivity.java:64)
at przemo.me.recommend.recommendme.SplashScreenActivity$DownloadData.doInBackground(SplashScreenActivity.java:56)
at android.os.AsyncTask$2.call(AsyncTask.java:304)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.widget.Toast$TN.<init>(Toast.java:346)
at android.widget.Toast.<init>(Toast.java:101)
at android.widget.Toast.makeText(Toast.java:260)
at przemo.me.recommend.recommendme.SplashScreenActivity$DownloadData$1.onFailure(SplashScreenActivity.java:103)
at com.loopj.android.http.JsonHttpResponseHandler.onFailure(JsonHttpResponseHandler.java:233)
at com.loopj.android.http.AsyncHttpResponseHandler.handleMessage(AsyncHttpResponseHandler.java:359)
at com.loopj.android.http.AsyncHttpResponseHandler.sendMessage(AsyncHttpResponseHandler.java:401)
at com.loopj.android.http.AsyncHttpResponseHandler.sendFailureMessage(AsyncHttpResponseHandler.java:319)
at com.loopj.android.http.AsyncHttpRequest.run(AsyncHttpRequest.java:109)
at com.loopj.android.http.SyncHttpClient.sendRequest(SyncHttpClient.java:95)
at com.loopj.android.http.AsyncHttpClient.get(AsyncHttpClient.java:1078)
at com.loopj.android.http.AsyncHttpClient.get(AsyncHttpClient.java:1037)
at przemo.me.recommend.recommendme.SplashScreenActivity$DownloadData.doInBackground(SplashScreenActivity.java:64)
at przemo.me.recommend.recommendme.SplashScreenActivity$DownloadData.doInBackground(SplashScreenActivity.java:56)
at android.os.AsyncTask$2.call(AsyncTask.java:304)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Crash 2
04-30 13:15:35.162 12349-12365/przemo.me.recommend.recommendme E/AsyncHttpRH: User-space exception detected!
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.widget.Toast$TN.<init>(Toast.java:346)
at android.widget.Toast.<init>(Toast.java:101)
at android.widget.Toast.makeText(Toast.java:260)
at przemo.me.recommend.recommendme.SplashScreenActivity$DownloadData$1.onFailure(SplashScreenActivity.java:103)
at com.loopj.android.http.JsonHttpResponseHandler.onFailure(JsonHttpResponseHandler.java:233)
at com.loopj.android.http.AsyncHttpResponseHandler.handleMessage(AsyncHttpResponseHandler.java:359)
at com.loopj.android.http.AsyncHttpResponseHandler.sendMessage(AsyncHttpResponseHandler.java:401)
at com.loopj.android.http.AsyncHttpResponseHandler.sendFailureMessage(AsyncHttpResponseHandler.java:319)
at com.loopj.android.http.AsyncHttpRequest.run(AsyncHttpRequest.java:109)
at com.loopj.android.http.SyncHttpClient.sendRequest(SyncHttpClient.java:95)
at com.loopj.android.http.AsyncHttpClient.get(AsyncHttpClient.java:1078)
at com.loopj.android.http.AsyncHttpClient.get(AsyncHttpClient.java:1037)
at przemo.me.recommend.recommendme.SplashScreenActivity$DownloadData.doInBackground(SplashScreenActivity.java:64)
at przemo.me.recommend.recommendme.SplashScreenActivity$DownloadData.doInBackground(SplashScreenActivity.java:56)
at android.os.AsyncTask$2.call(AsyncTask.java:304)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
You can not do UI operations from non UI thread. Like in your code you are showing Toast in Async task thread.
You should replace
Toast.makeText(SplashScreenActivity.this, "Turn on the internet and swipe to refresh.", Toast.LENGTH_SHORT).show();
with this
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(SplashScreenActivity.this, "Turn on the internet and swipe to refresh.", Toast.LENGTH_SHORT).show();
}
});
use -
SplashScreenActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(SplashScreenActivity.this, "Turn on the internet and swipe to refresh.", Toast.LENGTH_SHORT).show();
}
});
Here is a server connection AsyncTask task that I created years ago in Android Java. The background task works successfully. I used it to update in the background the data repository in the App I developed at that time.
public class DataExchangeStore extends Application {
public void startServerConnection(Context contextGlobal, Activity activityGlobal) {
this.contextGlobal = contextGlobal;
this.activityGlobal = activityGlobal;
connectTask = new ConnectTask();
connectTask.execute("");
}
private ConnectTask connectTask;
public class ConnectTask extends AsyncTask<String, String, TCPClient> {
#Override
protected TCPClient doInBackground(String... message) {
android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_BACKGROUND);
// we create a TCPClient object
mTcpClient = new TCPClient(new TCPClient.OnMessageReceived() {
#Override
// here the messageReceived method is implemented
public void messageReceived(ChatMessage message) {
// this method calls the onProgressUpdate
publishProgress(message.getMessage());
}
}, contextGlobal, activityGlobal);
mTcpClient.run();
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
System.err.println(values[0]);
// do your stuff here
}
}
Import is to permanently lock the screen orientation of the activity, specifying the screenOrientation attribute in the Android-Manifest file with portrait or landscape values:
<activity android:screenOrientation="portrait" />
Although previous answers are not wrong, using runOnUiThread() to jump out of the background thread in the AsyncTask is not a good practice. You have the onPostExecute() method for that.
What you should be doing is passing a result object to onPostExecute(). This object would encapsulate the result state (ie: error or success) and the actual data received. Then in onPostExecute() you check the result state and display a Toast if the state is error.
And do yourself a favor and replace your 20 TvSerie objects by a List<TvSerie> and do a loop in you AsyncTask to populate the list.
Please refer to the AsyncTask documentation for details on how to properly use it.
Solution:
The following worked fine, but I had two Activities already using my helper class, but forgot to add the Interface to one Activity.
So I got the TypeCastException.
But I did not realize I always looked at the wrong Activity, so I could not find the issue.
I currently write my first android service, which works fine.
Now I realized, that I have to bind unbind, check binding all over and so I thought to put all into a subclass and only do an interface with callbacks for the only functions I need.
But now i am stuck to call my interface functions
onTcBlueServiceConnected()
onTcBlueServiceDisconnected()
I simply want to prevent to write the same code over and over again.
Each activity I have to use the service, I extend from this helper class, instead of the AppCompatActivity.
Maybe I chose the wrong path, but lost with the right words for a search.
As far as I understand bound services, I have to bind from each activity I access the service, and unbind of course when it is destroyed.
So I thought this is a good approach
public abstract class TcBlueServiceHelper extends AppCompatActivity {
private static String LOG_TAG = "TcBlueServiceHelper";
TcBlueService mTcBlueService;
TcBlueService.TcBlueBinder myBinder;
boolean mServiceBound = false;
Context mCallingContext;
public TcBlueServiceHelper(Context callingContext) {
mCallingContext = callingContext;
}
public TcBlueServiceHelper(){
mCallingContext = this;
}
public void bindServiceSave(){
if (mServiceBound == false) {
Intent intent = new Intent(this, TcBlueService.class);
startService(intent);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
}
public void unbindServiceSave(){
if (mServiceBound) {
unbindService(mServiceConnection);
mServiceBound = false;
}
}
public TcBlueService.TcBlueBinder getBinder(){
return myBinder;
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
mServiceBound = false;
((ITcBlueServiceHelper)mCallingContext).onTCBServiceDisconnected(name);
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (TcBlueService.TcBlueBinder) service;
mTcBlueService = myBinder.getService();
mServiceBound = true;
((ITcBlueServiceHelper)mCallingContext).onTCBServiceConnected(name, service);
}
};
public interface ITcBlueServiceHelper{
public void onTCBServiceConnected(ComponentName name, IBinder service);
public void onTCBServiceDisconnected(ComponentName name);
}
}
My first thought to cast result in a "ClassCastException"
E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.ClassCastException: de.mobacomp.android.freightweight.StartActivity cannot be cast to de.mobacomp.android.freightweight.TcBlueServiceHelper$ITcBlueServiceHelper
at de.mobacomp.android.freightweight.TcBlueServiceHelper$1.onServiceConnected(TcBlueServiceHelper.java:72)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1068)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1085)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
I'm trying to have an app which simply starts a background service whenever a button is pressed. The background app should then open a connection using a socket to a server and then send some dummy data. After having done so, the service should die.
I'm currently getting a java.lang.IllegalStateException when I click the button and the whole application stops.
Here is what I have so far in my main activity.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void start_clicked(View view) {
Intent my_intent = new Intent(this,BackgroundService.class);
startActivity(my_intent);
}
}
Here is the XML corresponding to the button and to the background service:
This is Activity_Main.xml
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
android:id="#+id/button"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:onClick="start_clicked"/>
This is the Android Manifest corresponding to the service
<service android:name="com.example.g.backgroundsensor.BackgroundService"
android:exported="true"
android:enabled="true" >
</service>
And finally here is the actual BackgroundService class (fragments which I think caused the error)
public class BackgroundService extends Service {
private Socket my_socket;
public BackgroundService() {
try {
my_socket = new Socket(ip, 5000);
}catch(Exception e){
}
}
public int onStartCommand(Intent intent, int flags, int startId) {
try {
DataOutputStream my_stream = new DataOutputStream(my_socket.getOutputStream());
my_stream.write(121);
}catch(Exception e){
}
stopSelf();
return 1;
}
What is causing this error and how could I (in the future) debug this myself since the console is relatively vague:
---/com.example.g.backgroundsensor E/AndroidRuntime: FATAL EXCEPTION: main
---/com.example.g.backgroundsensor E/AndroidRuntime: Process: com.example.g.backgroundsensor, PID: 9876
---/com.example.g.backgroundsensor E/AndroidRuntime: java.lang.IllegalStateException: Could not execute method of the activity
To start a Service you should use startService() and not startActivity()
Intent my_intent = new Intent(this, BackgroundService.class);
startService(my_intent);
I don't know how one would debug that, but you should always make sure what you are calling where and which arguments you are passing.
First you have to create a Intent Service instead of service because intent service is called on UI thread and android doesn't allow any network call on UI thread take a look at code below
public class SocketService extends IntentService {
#Override
protected void onHandleIntent(Intent workIntent) {
//CONNECT SOCKET HERE
}
}
then register this service in Manifest
<application>
<service android:name=".SocketService" />
</application>
and then start your service like this
startService(new Intent(this, SocketService.class));
//YOU HAVE USED startActivity INSTEAD OF startService
I have a similar app and my Manifest only contains this:
<service android:name=".ServiceActivity" />
inside the application tag, just before activity tag. Besides that, your Manifest should explicit:
<uses-permission android:name="android.permission.INTERNET" />
There are two problems in this code.
To start a service that should run in background you need started service hence you need to call startservice() :
Intent my_intent = new Intent(this, BackgroundService.class);
startService(my_intent);
Second big problem is that the way you have created your service. It will by default start on UI thread. So, in this scenario you should have either use IntentService or service on a separate thread.
Intent Service :
public class BackgroundService extends IntentService {
private Socket my_socket;
#Override
protected void onHandleIntent(Intent workIntent) {
try {
my_socket = new Socket(ip, 5000);
DataOutputStream my_stream = new DataOutputStream(my_socket.getOutputStream());
my_stream.write(121);
}catch(Exception e){
}
}
}
Major benefit of intent service is that it will call stopSelf once all the work is done and there are no more requests. Second is that all the work will be done in background.
Service on a seperate thread :
public class BackgroundService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
I would suggest using intentservice as it is simple and perfect for your scenario.
What is causing this error
startActivity is called instead of startService
how could I (in the future) debug this myself since the console is relatively vague
This is the interesting part, the message should be followed by a full stack trace, that is explicitly describing the error. Like this one :
02-10 12:26:52.734: E/AndroidRuntime(16214): FATAL EXCEPTION: main
02-10 12:26:52.734: E/AndroidRuntime(16214): Process: com.example.sandbox, PID: 16214
02-10 12:26:52.734: E/AndroidRuntime(16214): java.lang.IllegalStateException: Could not execute method for android:onClick
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.view.View$DeclaredOnClickListener.onClick(View.java:4458)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.view.View.performClick(View.java:5204)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.view.View$PerformClick.run(View.java:21153)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.os.Handler.handleCallback(Handler.java:739)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.os.Handler.dispatchMessage(Handler.java:95)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.os.Looper.loop(Looper.java:148)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.app.ActivityThread.main(ActivityThread.java:5417)
02-10 12:26:52.734: E/AndroidRuntime(16214): at java.lang.reflect.Method.invoke(Native Method)
02-10 12:26:52.734: E/AndroidRuntime(16214): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
02-10 12:26:52.734: E/AndroidRuntime(16214): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
02-10 12:26:52.734: E/AndroidRuntime(16214): Caused by: java.lang.reflect.InvocationTargetException
02-10 12:26:52.734: E/AndroidRuntime(16214): at java.lang.reflect.Method.invoke(Native Method)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.view.View$DeclaredOnClickListener.onClick(View.java:4453)
02-10 12:26:52.734: E/AndroidRuntime(16214): ... 9 more
02-10 12:26:52.734: E/AndroidRuntime(16214): Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.example.sandbox/com.example.sandbox.BackgroundService}; have you declared this activity in your AndroidManifest.xml?
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1794)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.app.Instrumentation.execStartActivity(Instrumentation.java:1512)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.app.Activity.startActivityForResult(Activity.java:3930)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.app.Activity.startActivityForResult(Activity.java:3890)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.app.Activity.startActivity(Activity.java:4213)
02-10 12:26:52.734: E/AndroidRuntime(16214): at android.app.Activity.startActivity(Activity.java:4181)
02-10 12:26:52.734: E/AndroidRuntime(16214): at com.example.sandbox.MainActivity.start_clicked(MainActivity.java:19)
02-10 12:26:52.734: E/AndroidRuntime(16214): ... 11 more
The part Unable to find explicit activity class com.example.sandbox/com.example.sandbox.BackgroundService}; have you declared this activity in your AndroidManifest.xml? is very clear and it should be easy to fix the issue just reading it.
I am developing my first android app. I have been created a Service class which role is to check if any new information on an external webpage. The HTTP request and service work as i should, but after a while I get these OutOfMemoryError.
Are someone able to see where the Service gather all that memory?
Error message 1.
java.lang.OutOfMemoryError: pthread_create (stack size 16384 bytes) failed: Try again
at java.lang.VMThread.create(Native Method)
at java.lang.Thread.start(Thread.java:1029)
at org.apache.http.impl.conn.tsccm.AbstractConnPool.enableConnectionGC(AbstractConnPool.java:140)
at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager.createConnectionPool(ThreadSafeClientConnManager.java:120)
at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager.(ThreadSafeClientConnManager.java:98)
at com.loopj.android.http.AsyncHttpClient.(AsyncHttpClient.java:210)
at com.loopj.android.http.AsyncHttpClient.(AsyncHttpClient.java:149)
at com.loopj.android.http.AsyncHttpClient.(AsyncHttpClient.java:119)
at com.quickit.app.MyService.checkUpdates(MyService.java:89)
at com.quickit.app.MyService.access$1(MyService.java:75)
at com.quickit.app.MyService$TimeDisplayTimerTask$1.run(MyService.java:68)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5105)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
at dalvik.system.NativeStart.main(Native Method)
Error message 2.
java.lang.OutOfMemoryError: thread creation failed
at java.lang.VMThread.create(Native Method)
at java.lang.Thread.start(Thread.java:1050)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:913)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1295)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:81)
at com.loopj.android.http.AsyncHttpClient.sendRequest(AsyncHttpClient.java:893)
at com.loopj.android.http.AsyncHttpClient.post(AsyncHttpClient.java:688)
at com.loopj.android.http.AsyncHttpClient.post(AsyncHttpClient.java:671)
at com.loopj.android.http.AsyncHttpClient.post(AsyncHttpClient.java:658)
at com.quickit.app.MyService.checkUpdates(MyService.java:90)
at com.quickit.app.MyService.access$1(MyService.java:75)
at com.quickit.app.MyService$TimeDisplayTimerTask$1.run(MyService.java:68)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:5092)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:564)
at dalvik.system.NativeStart.main(Native Method)
My service class.
public class MyService extends Service {
boolean login = false;
// constant
public static final long NOTIFY_INTERVAL = 10 * 1000; // 10 seconds
String address = Utilities.getAPIUrl();
// run on another Thread to avoid crash
private Handler mHandler = new Handler();
// timer handling
private Timer mTimer = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
SharedPreferences prefs = getSharedPreferences("com.quickit.app", Context.MODE_PRIVATE);
login = prefs.getBoolean("login", false);
// cancel if already existed
if(mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
}
public class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
if(login) {
checkUpdates();
}
}
});
}
}
private void checkUpdates() {
final SharedPreferences prefs = getSharedPreferences("com.quickit.app", Context.MODE_PRIVATE);
final String from_id = prefs.getInt("user", 0)+"";
final String lastCheck = prefs.getString("last_check", "0");
RequestParams params = new RequestParams();
params.put("type", "get_ask_questions");
params.put("fromid", from_id);
params.put("last_check", lastCheck);
AsyncHttpClient client = new AsyncHttpClient();
client.post(address, params, new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String response) {
try {
notification(response);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
Your code is constantly creating a new AsyncHttpClient object every time that timer expires! If the object never finishes its work, at some point, you will run out of memory.
Since you are just periodically checking for updates, you should make the AsyncHttpClient object static and just reuse it.
Look at http://loopj.com/android-async-http/ specifically, the Recommended Usage section.
i have a service running which receive broadcast messages in LAN and i have started the service from fragment and i want to stop the service when the fragment is destroyed but its giving NPE when i call stopservice.
My service calling fragment is:
public class Receive extends Fragment {
TextView tv1,tv2;
Intent intent;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView =inflater.inflate(R.layout.receive, container, false);
intent = new Intent(getActivity(), Server.class);
tv1=(TextView)rootView.findViewById(R.id.textView1);
tv2=(TextView)rootView.findViewById(R.id.textView2);
//getActivity().startService(intent);
return rootView;
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateUI(intent);
}};
private void updateUI(Intent intent) {
Toast.makeText(getActivity().getApplicationContext(), "Yea!!! Service called", Toast.LENGTH_SHORT).show();
String message = intent.getStringExtra("messages");
String senderip = intent.getStringExtra("sender");
tv2.setText(message);
tv1.setText(senderip);
}
#Override
public void onResume() {
super.onResume();
getActivity().startService(intent);
getActivity().registerReceiver(broadcastReceiver, new IntentFilter(
Server.UDP_BROADCAST));
Log.i("UDP", "reg started");
}
#Override
public void onPause() {
super.onPause();
getActivity(). unregisterReceiver(broadcastReceiver);
getActivity().stopService(intent);
Log.i("UDP", "unreg started");
}
}
My service is:
public class Server extends Service {
static String UDP_BROADCAST = "soft.b.peopleassist";
//Boolean shouldListenForUDPBroadcast = false;
DatagramSocket socket;
//Intent intent;
private void listenAndWaitAndThrowIntent(InetAddress broadcastIP, Integer port) throws Exception {
byte[] recvBuf = new byte[15000];
if (socket == null || socket.isClosed()) {
socket = new DatagramSocket(port, broadcastIP);
socket.setBroadcast(true);
}
//socket.setSoTimeout(1000);
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
Log.e("UDP", "Waiting for UDP broadcast");
socket.receive(packet);
String senderIP = packet.getAddress().getHostAddress();
String message = new String(packet.getData());
Log.e("UDP", "Got UDB broadcast from " + senderIP + ", message: " + message);
broadcastIntent(senderIP, message);
socket.close();
}
private void broadcastIntent(String senderIP, String message) {
Intent intent = new Intent(Server.UDP_BROADCAST);
intent.putExtra("sender", senderIP);
intent.putExtra("messages", message);
sendBroadcast(intent);
}
Thread UDPBroadcastThread;
void startListenForUDPBroadcast() {
UDPBroadcastThread = new Thread(new Runnable() {
public void run() {
try {
InetAddress broadcastIP = InetAddress.getByName("192.168.1.255"); //172.16.238.42 //192.168.1.255
Integer port = 11111;
while (shouldRestartSocketListen) {
listenAndWaitAndThrowIntent(broadcastIP, port);
}
//if (!shouldListenForUDPBroadcast) throw new ThreadDeath();
} catch (Exception e) {
Log.i("UDP", "no longer listening for UDP broadcasts cause of error " + e.getMessage());
}
}
});
UDPBroadcastThread.start();
}
private Boolean shouldRestartSocketListen=true;
void stopListen() {
shouldRestartSocketListen = false;
socket.close();
}
#Override
public void onCreate() {
};
#Override
public void onDestroy() {
stopListen();
//stopService(intent);
Log.i("UDP", "Service stoped");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
shouldRestartSocketListen = true;
startListenForUDPBroadcast();
Log.i("UDP", "Service started");
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
My logcat is:
09-03 09:17:21.995: D/gralloc_goldfish(908): Emulator without GPU emulation detected.
09-03 09:17:28.763: I/UDP(908): reg started
09-03 09:17:28.853: I/UDP(908): Service started
09-03 09:17:28.993: I/UDP(908): no longer listening for UDP broadcasts cause of error bind failed: EADDRNOTAVAIL (Cannot assign requested address)
09-03 09:17:30.653: I/UDP(908): unreg started
09-03 09:17:30.893: D/AndroidRuntime(908): Shutting down VM
09-03 09:17:30.893: W/dalvikvm(908): threadid=1: thread exiting with uncaught exception (group=0x409961f8)
09-03 09:17:30.963: E/AndroidRuntime(908): FATAL EXCEPTION: main
09-03 09:17:30.963: E/AndroidRuntime(908): java.lang.RuntimeException: Unable to stop service soft.b.peopleassist.Server#4137dbb8: java.lang.NullPointerException
09-03 09:17:30.963: E/AndroidRuntime(908): at android.app.ActivityThread.handleStopService(ActivityThread.java:2405)
09-03 09:17:30.963: E/AndroidRuntime(908): at android.app.ActivityThread.access$2000(ActivityThread.java:122)
09-03 09:17:30.963: E/AndroidRuntime(908): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1212)
09-03 09:17:30.963: E/AndroidRuntime(908): at android.os.Handler.dispatchMessage(Handler.java:99)
09-03 09:17:30.963: E/AndroidRuntime(908): at android.os.Looper.loop(Looper.java:137)
09-03 09:17:30.963: E/AndroidRuntime(908): at android.app.ActivityThread.main(ActivityThread.java:4340)
09-03 09:17:30.963: E/AndroidRuntime(908): at java.lang.reflect.Method.invokeNative(Native Method)
09-03 09:17:30.963: E/AndroidRuntime(908): at java.lang.reflect.Method.invoke(Method.java:511)
09-03 09:17:30.963: E/AndroidRuntime(908): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
09-03 09:17:30.963: E/AndroidRuntime(908): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
09-03 09:17:30.963: E/AndroidRuntime(908): at dalvik.system.NativeStart.main(Native Method)
09-03 09:17:30.963: E/AndroidRuntime(908): Caused by: java.lang.NullPointerException
09-03 09:17:30.963: E/AndroidRuntime(908): at soft.b.peopleassist.Server.stopListen(Server.java:68)
09-03 09:17:30.963: E/AndroidRuntime(908): at soft.b.peopleassist.Server.onDestroy(Server.java:78)
09-03 09:17:30.963: E/AndroidRuntime(908): at android.app.ActivityThread.handleStopService(ActivityThread.java:2388)
09-03 09:17:30.963: E/AndroidRuntime(908): ... 10 more
09-03 09:17:33.533: I/Process(908): Sending signal. PID: 908 SIG: 9
Thanks in Advance.
In the stopListen() method you set the stop boolean and then immediately close the socket.
It is possible, that your other thread is deeply in work with that. I would suggest, that you close sockets in the thread in which they where created. e.g. socket.close() in the catchblock and remove it from stopListen().