I created an activity that calls a service and the service creates a Thread that send and receive some data to/from the server, I can open other apps and the Service and the Thread run ok, but when I close the activity, the Service keeps running but the thread stops working. Why??? How can I keep the Thread running!!.
Code
Activity
package com.connectus.app;
public class ConnectUsActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_connect_us);
Intent startServiceIntent = new Intent(getApplicationContext(), ConnectUsService.class);
startService(startServiceIntent);
}
Service
package com.connectus.app;
public class ConnectUsService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Thread t=new Thread(new Runnable() {
private DataInputStream in;
private BufferedReader br;
private DataOutputStream out;
#Override
public void run() {
Socket server=null;
try{
server=new Socket("10.10.40.58",4444);
in = new DataInputStream(server.getInputStream());
br=new BufferedReader(new InputStreamReader(in));
out = new DataOutputStream(server.getOutputStream());
while(true){
out.writeUTF("aaaaa");
String leido=in.readUTF();
out.writeUTF("asdf");
Thread.sleep(60000);
}
}catch(IOException ioe){
ioe.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
}
});
t.start();
return START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
This is just a part of my code, I hope it helps.
Thanks everyone, finally i find a solution. It was necesary to use the setForeground() method, I just added this code to my service Class:
Notification note=new Notification();
startForeground(1337, note);
According to my research, this code is used to prevent that the service get killed by itself.
best regards!
Related
I am working with images to send on the device, that works fine when I am using Async Task it works well but the problem is when I do it via Service it doesn't work and I get this error, "Unable to start Service with intent caused by "NetworkOnMainThreadException"". I am actually passing the byte[] from MainActivity to Service
I need to use service because OnReceive method of BroadcastReceiver cannot respond to Async task.
Thank you!
In the Mainfest.xml
<service android:name=".SendImageClientService"/>
MainActivity
private BroadcastReceiver wifiStateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int wifiStateExtra = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
if(wifiStateExtra==WifiManager.WIFI_STATE_ENABLED){
sendingDrawableImage();
}else if(wifiStateExtra==WifiManager.WIFI_STATE_DISABLED){
Toast.makeText(context, "Please Check Your Internet Connection", Toast.LENGTH_SHORT).show();
}
}
};
private void sendingDrawableImage() {
drawable = (BitmapDrawable) imageView.getDrawable();
bitmap = drawable.getBitmap();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
byte[] array = byteArrayOutputStream.toByteArray();
Intent serviceIntent=new Intent(this,SendImageClientService.class);
serviceIntent.putExtra("byte",array);
this.startService(serviceIntent);
}
#Override
protected void onStart() {
super.onStart();
IntentFilter intentFilter = new
IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
registerReceiver(wifiStateReceiver, intentFilter);
}
Service class
public class SendImageClientService extends Service {
Handler handler = new Handler(Looper.getMainLooper());
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
byte[] bytesss=intent.getByteArrayExtra("byte");
Socket socket = new Socket("ip_address_here", 8888);
OutputStream out = socket.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(out);
dataOutputStream.write(bytesss);
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(SendImageClientService.this, "Image sent", Toast.LENGTH_SHORT).show();
}
});
dataOutputStream.close();
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
the documentation says:
Caution: A service runs in the main thread of its hosting process; the
service does not create its own thread and does not run in a separate
process unless you specify otherwise. If your service is going to
perform any CPU-intensive work or blocking operations, such as MP3
playback or networking, you should create a new thread within the
service to complete that work. By using a separate thread, you can
reduce the risk of Application Not Responding (ANR) errors, and the
application's main thread can remain dedicated to user interaction
with your activities.
https://developer.android.com/guide/components/services
so, you need to create new thread in your service for a long operation.
Also, you need to know, that Services are using for a long background tasks and IntentServices are using for a short background tasks. But IntentService work in separate thread.
You can use something like this:
new Handler().post(runnable)
where runnable is your long operation action (like internet action or database action). Handler is a specific class for working with thread in android.
Edit.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
handler.post(new Runnable() {
#Override
public void run() {
byte[] bytesss=intent.getByteArrayExtra("byte");
Socket socket = new Socket("ip_address_here", 8888);
OutputStream out = socket.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(out);
dataOutputStream.write(bytesss);
dataOutputStream.close();
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
return START_STICKY;
}
I'm trying to call a service class from another service class but I get this error:
android.content.Context.getPackageName() on a null object reference
Do you know how I call service from another service?
When I setup my app to phone first, a broadcastreceiver is starting Alarm class and in Alarm class, I want to start another service in ReadGmail() method. But I get that null object reference error.
Here is my code:
public class Alarm extends Service {
private String userName;
private String password;
private String receivingHost;
Context context;
public int onStartCommand(Intent intent, int flags, int startId) {
final Handler handler = new Handler();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String senderPassword=new String("password");
String senderUserName=new String("username#gmail.com");
Alarm newGmailClient=new Alarm();
newGmailClient.setAccountDetails(senderUserName, senderPassword);
newGmailClient.readGmail();
}
});
}
};
Timer timer = new Timer();
timer.schedule(doAsynchronousTask, 10, 120000);
return super.onStartCommand(intent, flags, startId);
};
public void setAccountDetails(String userName,String password){
this.userName=userName;//sender's email can also use as User Name
this.password=password;
}
public void readGmail(){
this.receivingHost="imap.gmail.com";//for imap protocol
Properties props2=System.getProperties();
props2.setProperty("mail.store.protocol", "imaps");
Session session2=Session.getInstance(props2, null);
try {
Store store=session2.getStore("imaps");
store.connect(this.receivingHost,this.userName, this.password);
Folder folder=store.getFolder("INBOX");//get inbox
folder.open(Folder.READ_ONLY);//open folder only to read
Message message[]=folder.getMessages();
String key= "Hey";
String subject;
for(int i=0;i<message.length;i++){
System.out.println(message[i].getSubject());
subject=message[i].getSubject();
if(subject.equals(key)){
System.out.println("inside");
Intent mTutorial = new Intent(Alarm.this, LaunchActivity.class);
this.startService(mTutorial);
//I want to call service class in here. LaunchActivity is my service class.
}
//Log.d(message[i].getSubject(),message[i].getSubject());
}
folder.close(true);
store.close();
} catch (Exception e) {
System.out.println(e.toString());
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.d("", "FirstService destroyed");
}
}
This is your problem:
Alarm newGmailClient=new Alarm();
Your Alarm class extends Service. It is an Android Service. You cannot create an instance of an Android component with new. Only Android can create Android components. If you want to start a Service, you call startService.
Why do you want to start another Service? Please explain.
Use an interface your Service will use to communicate events:
public interface ServiceCallbacks {
void doSomething();
}
I'm trying to launch service and then open socket to have connection with server.
On button click I create new Thread and then start service.
Thread t = new Thread(){
public void run(){
mIntent= new Intent(MainActivity.this, ConnectonService.class);
mIntent.putExtra("KEY1", "Value used by the service");
context.startService(mIntent);
}
};
t.start();
Then on service, I try to open socket and have connection with server
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO do something useful
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
Scanner scanner = new Scanner(socket.getInputStream());
message = scanner.nextLine();
} catch (IOException e) {
e.printStackTrace();
}
return Service.START_NOT_STICKY;
}
But when I call it, I have error
08-30 08:56:49.268: E/AndroidRuntime(3751): java.lang.RuntimeException: Unable to start service com.example.testofconnection.ConnectonService#40ef02a8 with Intent { cmp=com.example.testofconnection/.ConnectonService (has extras) }: android.os.NetworkOnMainThreadException*
I think problem is that service is on main thread, but I can't find how should I start service on new (independend) thread to keep connection alive?
You can use IntentService for this. Just launch it normally with an Intent from the main thread. onHandleIntent() method gets executed in background thread. Put your socket-code in there. Here is an example code.
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
// this method is called in background thread
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
In your activity you start the service as following.
startService(new Intent(this, MyIntentService.class));
If you need a long-lasting service, you can create a normal service and start a thread there. Here is an example. Make sure you launch it as "foreground" service. This will allow service to run longer without been killed by Android.
public class MyAsyncService extends Service {
private AtomicBoolean working = new AtomicBoolean(true)
private Runnable runnable = new Runnable() {
#Override
public void run() {
while(working.get()) {
// put your socket-code here
...
}
}
}
#Override
public void onCreate() {
// start new thread and you your work there
new Thread(runnable).start();
// prepare a notification for user and start service foreground
Notification notification = ...
// this will ensure your service won't be killed by Android
startForeground(R.id.notification, notification);
}
#Override
public onDestroy() {
working.set(false)
}
}
Move this code to your thread:
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
Scanner scanner = new Scanner(socket.getInputStream());
message = scanner.nextLine();
} catch (IOException e) {
e.printStackTrace();
}
Just as an example (I'm not sure it this fits to your task):
Thread t = new Thread(){
public void run(){
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
Scanner scanner = new Scanner(socket.getInputStream());
message = scanner.nextLine();
} catch (IOException e) {
e.printStackTrace();
}
mIntent= new Intent(MainActivity.this, ConnectonService.class);
mIntent.putExtra("KEY1", "Value used by the service");
context.startService(mIntent);
}
};
t.start();
You should know that a service is running on the UI thread, so you got this error. Check this nice site for more information about various threading approaches in Android.
I am trying to write an Android application which receives a Datagram packet and plays that packet (audio packet).
I want to use a Service for this purpose so there is not interruption in the audio. For this I have a service like this:
public class MyService extends Service {
...
AudioTrack track;
DatagramSocket sock;
DatagramPacket pack;
...
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
...
track = new AudioTrack(...)
track.play();
sock = new DatagramSocket(AUDIO_PORT);
pack = new DatagramPacket(...)
...
}
#Override
public void onStart(Intent intent, int startid) {
...
while(true)
{
try {
sock.receive(pack);
} catch (IOException e) {
e.printStackTrace();
}
track.write(pack.getData(), 0, pack.getLength());
}
}
}
In my main activity I have a "START" button which when it is pressed it runs:
startService(new Intent(this, MyService.class));
The app works fine and plays the received audio well, however after pressing the start button:
It does not respond to any other button
After a while I get this message: "Application MyAppName is not responding" and it gives two options Forceclose and Wait. If I press Wait the audo continues to play nicely but the UI is not responding anymore.
To me it looks like putting while(true) in the onStart may have caused this.
Any help and pointer in doing this in a correct way is appreciated.
Here's an example:
public void onStart(Intent intent, int startid) {
...
Thread streamer = new Thread() {
#Override
public void run() {
while(true) {
try {
sock.receive(pack);
} catch (IOException e) {
e.printStackTrace();
}
track.write(pack.getData(), 0, pack.getLength());
}
}
});
streamer.setPriority( Thread.MAX_PRIORITY );
streamer.start();
}
Obviously, in the final version of your code, you will want to keep track of the Thread you create so that you can check its status or terminate it, and/or create a Handler in the thread so that you can control it from the service.
I'm trying to implement a service to handle the communication with the server for the following code. I don't know much about the design architecture for these.
Here is my service class
public class BgService extends Service {
private static final String TAG = BgService.class.getSimpleName();
private Timer timer;
SendJsonRequest sjr;
private TimerTask updateTask = new TimerTask(){
#Override
public void run(){
try{
SendJsonRequest sjr = new SendJsonRequest();
sjr.carMake();
Log.i(TAG, "LOOK AT ME");
}
catch(Exception e){
Log.w(TAG,e);
}
}
};
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate(){
super.onCreate();
Log.i(TAG, "Service creating");
timer = new Timer("Server listening timer");
timer.schedule(updateTask, 1000L, 60*1000L);
}
#Override
public void onDestroy(){
super.onDestroy();
Log.i(TAG, "Service Destroying");
timer.cancel();
timer = null;
}
}
Here is my SendJsonRequest class
public class SendJsonRequest{
private static final String TAG = "SendJsonRequest";
private static String URL = "xxxxxxxxx";
private static String infoRec;
public static void createJsonObj(String path, Map x){
infoRec = CreateJsonRequest.jsonRequest(URL+path, x );
System.out.println(infoRec);
}
public static void carMake(){
String path = "/CarMake";
Map<String, Object> z = new HashMap<String,Object>();
z.put("Name", "Ford");
z.put("Model", "Mustang");
createJsonObj(path, z);
}
}
Here is my CreateJsonObject class
public class CreateJsonRequest {
public static String jsonRequest(String URL, Map<String,Object> params){
try{
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(URL);
JSONObject holder = new JSONObject();
for (Map.Entry<String, Object> m : params.entrySet()){
try {
holder.put(m.getKey(), m.getValue());
}
catch (JSONException e) {
Log.e("Hmmmm", "JSONException : "+e);
}
}
StringEntity se;
se = new StringEntity(holder.toString());
httpPost.setEntity(se);
httpPost.setHeader("Accept", "text/json");
httpPost.setHeader("Content-type", "text/json");
HttpResponse response = (HttpResponse) httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
if(entity != null){
InputStream is = entity.getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
String result= convertToString(is);
is.close();
System.out.println(result);
return result;
}
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
Sorry for the massive amount of code. How I implemented my service is obviously not correct, I just have no clue where to start to get a service handling the json requests to the server. Thanks in advance.
To be more clear, this did work on a button click, now I'm trying to get it to all run in the background with the service. So I guess my question is what goes where in the service?
My activity successfully starts the service, the service would work and print "look at me" to the logcat every minute. Then I added the try{ sjr.carMake()} and it catches an exception.
You can use a broadcast receiver. This is a way to have your code start at certain times indicated by Android OS - for example, you can have it start when Android finished booting up (this is where I run my services usually.
The best way is to use the AlarmManager class, and tell your service how often to run.
Tell us more about what you're trying to do, and what the problem is, and we can give you a more concise answer...
UPDATE:
Have you created an entry in the manifest.xml file for the service?
UPDATE
Here is how I'm doing it in my application. This is your "hook" to the OS. It's going to fire when it finishes booting (don't forget to make in entry in the manifest for this!)
public class TmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent bootintent) {
try{
Log.i("Taskmotion-ROBOT", "Robot Broadcast signal received on Boot. Trying to start Alarm scheduler");
Intent mServiceIntent = new Intent(context, ServiceAlarm.class);
context.startService(mServiceIntent);
}
catch(Exception e)
{
Log.i("Taskmotion", "Failed to start service...");
}
}
}
This Broadcast receiver calls a service that implements the AlarmManager class. The alarm manager sets up a schedule to run my service at a specified interval. Note that the alarms are deleted when the phone is shut down - but then recreated again when process is repeated as the phone boots back up and runs the BroadcastReceiver again.
public class ServiceAlarm extends Service {
private PendingIntent mAlarmSender;
#Override
public void onCreate() {
try{
Log.i("Taskmotion-ROBOT", "Setting Service Alarm Step 1");
mAlarmSender = PendingIntent.getService(this.getApplicationContext(),
0, new Intent(this.getApplicationContext(), BackgroundService.class), 0);
}
catch(Exception e)
{
Log.i("Taskmotion-ROBOT", "Problem at 1 :" + e.toString());
}
long firstTime = SystemClock.elapsedRealtime();
Log.i("Taskmotion-ROBOT", "Setting Service Alarm Step 2");
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME,
firstTime, AlarmManager.INTERVAL_HOUR, mAlarmSender);
this.stopSelf();
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
I haven't refactored this code yet, it was my first go at it. I see now that I'm looking at it again that I could probably do the scheduling inside the BroadcastReceiver, but for the sake of getting you something that works, I'll continue.
As indicated by AlarmManager.INTERVAL_HOUR, my service will run once an hour. The service that I want to run is defined in the pendingIntent (BackgroundService.class). This is where you put your own service class.
I reworked your service class for you, and removed the timer (functionality replaced by the BroadcastReceiver & AlarmManager).
public class BgService extends Service {
private static final String TAG = BgService.class.getSimpleName();
SendJsonRequest sjr;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate(){
super.onCreate();
Log.i(TAG, "Service creating");
//DO YOUR WORK WITH YOUR JSON CLASS HERE
//**************************************
//Make sure to call stopSelf() or your service will run in the background, chewing up
//battery life like rocky mountain oysters!
this.stopSelf();
}
#Override
public void onDestroy(){
super.onDestroy();
}
}