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.
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 have a UDP Server/Client running in background with Service, these are my operations:
I launch the app
The Service starts
I close the app but the Service is running in background (this is
what I want)
I send udp message and the phone receives correctly and answer me
I don't send messages for about 5 minutes
I send message, my phone doesn't answer me
I try to send another message again, my phone now answer
How could it happen? My App seems to sleep and wake up when I send the first message but it could answer only the second or sometimes I need 4-5 messages before get an answer, maybe is this latency or other?
If I flood my App it always will answer me correctly, but if I don't send messages for an amount of time it will cause the problem.
I want my App answer me everytime, even if the app is closed or the phone is locked.
This is my code:
public class UDPListenerService extends Service {
DatagramSocket socket;
private Boolean shouldRestartSocketListen = true;
Thread UDPBroadcastThread;
private void listenAndWaitAndThrowIntent() throws Exception {
try {
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
DatagramSocket serverSocket = new DatagramSocket(9876);
while (true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
InetAddress IPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
String capitalizedSentence = sentence.toUpperCase();
sendData = capitalizedSentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
receiveData = new byte[1024];
}
} catch (Exception e) {
}
}
void startListenForUDPBroadcast() {
UDPBroadcastThread = new Thread(new Runnable() {
public void run() {
try {
while (shouldRestartSocketListen) {
listenAndWaitAndThrowIntent();
}
//if (!shouldListenForUDPBroadcast) throw new ThreadDeath();
} catch (Exception e) {
Log.i("UDP", "no longer listening for UDP broadcasts cause of error " + e.getMessage());
}
}
});
UDPBroadcastThread.start();
}
#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;
}
#Override
public void onCreate() {
}
#Override
public void onDestroy() {
stopListen();
}
void stopListen() {
shouldRestartSocketListen = false;
socket.close();
}
}
The reason your app stops is because the service is put to sleep by the system. Maybe you need use the bindService() method in the calling activity.
Check https://developer.android.com/guide/components/services.html for more info about the methods and the lifecycles of services.
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!
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 developing an Android application.
This application will have a server to start a DatagramSocket as a server. It will wait for incoming message. When the socket get a message I will process it.
To start a UDP Server socket I'm going to use a Local Service. This service will have a worker thread where I'm going to listen to incoming messages.
This is my unfinished Local Service implementation:
public class UDPSocketBackgroundService extends Service
{
private static final String TAG = "UDPSocketBackgroundService";
private ThreadGroup myThreads = new ThreadGroup("UDPSocketServiceWorker");
private Handler mServiceHandler;
#Override
public void onCreate()
{
super.onCreate();
Log.v(TAG, "in onCreate()");
}
#Override
public IBinder onBind(Intent arg0)
{
try
{
new Thread(myThreads, new UDPServerThread("X", 8888)).start();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
And this is my also unfinished Worker Thread implementation:
public class UDPServerThread extends Thread
{
private static final int MESSAGE_SIZE = 256;
protected DatagramSocket socket = null;
protected boolean end = false;
public UDPServerThread(String serverName, int port) throws IOException
{
super(serverName);
socket = new DatagramSocket(port);
}
public void run()
{
while (!end)
{
try
{
byte[] buf = new byte[MESSAGE_SIZE];
// Wait an incoming message.
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
// TODO: Notify Service with packet received
}
catch (IOException e)
{
// TODO Mensaje de error.
e.printStackTrace();
}
}
}
}
Those classes have their own file (they are on different files).
Here:
socket.receive(packet);
//TODO: Notify Service with packet received
How can I notify service that we have received a packet? I want to send to service that packet also.
Here there is an example on how to communicate from Main thread to worker thread. But, I don't need that, I'm looking for an example on how to communicate from worker thread to service.
I've found this example, but I don't understand it very well because on that example both classes are declare it on the same file.
As you can see, I'm a newbie on Android development.
If you know a better approach, please tell me.
When you create the UDPServerThread, you could pass in a reference to the UDPSocketBackgroundService and then call a method on it (processPacket() for example) when packets are received. This processPacket() method will need to use some sort of synchronization.
Here's a small code excerpt of the related functions:
public class UDPSocketBackgroundService extends Service
{
....
#Override
public IBinder onBind(Intent arg0)
{
try
{
new Thread(myThreads, new UDPServerThread(this, "X", 8888)).start();
// Notice we're passing in a ref to this ^^^
}
...
}
public void processPacket(DatagramPacket packet)
{
// Do what you need to do here, with proper synchronization
}
}
public class UDPServerThread extends Thread
{
private static final int MESSAGE_SIZE = 256;
protected DatagramSocket socket = null;
protected boolean end = false;
protected UDPSocketBackgroundService = null;
public UDPServerThread(UDPSocketBackgroundService service, String serverName, int port) throws IOException
{
super(serverName);
this.service = service;
socket = new DatagramSocket(port);
}
...
public void run()
{
while (!end)
{
try
{
byte[] buf = new byte[MESSAGE_SIZE];
// Wait an incoming message.
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
service.processPacket(packet);
}
...
}
...
}
}
Notice that going this approach, the UDPSocketBackgroundService is now "tightly coupled" with the UDPServerThread. Once you get this working, you may consider refactoring it with a more elegant design where there is less coupling, but for now this should get you going :)