2013-08-30 8 views
6

Próbuję uruchomić service, a następnie otworzyć socket, aby uzyskać połączenie z serwerem.Jak uruchomić usługę, nie w głównym wątku?

Po kliknięciu przycisku Tworzę nowy Thread, a następnie uruchom serwis.

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(); 

Następnie na service, próbuję otworzyć socket i mieć połączenie z serwerem

@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; 
} 

Ale kiedy ja to nazywam, mam błąd

08-30 08:56:49.268: E/AndroidRuntime(3751): java.lang.RuntimeException: Unable to start service [email protected] with Intent { cmp=com.example.testofconnection/.ConnectonService (has extras) }: android.os.NetworkOnMainThreadException* 

myślę problemem jest że service jest na main thread, ale nie mogę znaleźć, jak powinienem uruchomić usługę na nowym (niezależnym) t hread zachować connection alive?

+0

Muszę utrzymywać połączenie z serwerem przy życiu. AsyncTask otwiera tylko połączenie, wysyła jakieś żądanie, otrzymuje odpowiedź i zamyka, więc dzięki usłudze mogę ją zaimplementować: – Ragaisis

+0

http://developer.android.com/guide/components/services.html. sprawdź temat w rozszerzeniu klasy usługi – Raghunandan

Odpowiedz

9

Możesz użyć IntentService do tego. Wystarczy uruchomić go normalnie z intencją z głównego wątku. onHandleIntent() metoda zostaje wykonana w wątku w tle. Umieść tam swój kod gniazda. Oto przykładowy kod.

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; 
    } 

} 

W swojej działalności możesz uruchomić usługę w następujący sposób.

startService(new Intent(this, MyIntentService.class)); 

Jeśli potrzebujesz długotrwałej usługi, możesz utworzyć normalną usługę i rozpocząć tam wątek. Oto przykład. Upewnij się, że uruchamiasz go jako usługę "pierwszego planu". Pozwoli to na dłuższą pracę usługi bez zabicia przez system Android.

public class MyAsyncService extends Service { 

    private Runnable runnable = new Runnable() { 
     @Override 
     public void run() { 
      while(true) { 
       // 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); 
    } 
} 
+2

Ale czytam, że IntentService jest tylko dla jednego zadania czasowego. Powinienem utrzymywać połączenie za pomocą gniazda, wysłać pewne żądanie do serwera, odebrać odpowiedź i wysłuchać poleceń serwera. Jest to dość trudne zadanie długoterminowe. Czy mogę zaimplementować IntentService? – Ragaisis

+3

@Ragaisis Powinieneś lepiej używać normalnej usługi z gwintem. Zaktualizowałem swoją odpowiedź. czy to pomaga? –

+0

Całkowicie zgadzam się z tą odpowiedzią, ale mam jedno pytanie, na które nie możemy się posunąć i użyć bezpośrednio nici zamiast używać jej w serwisie? Mam na myśli to, co czyni go innym.? – Bhagyashri

3

przenieść ten kod do wątku:

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(); 
} 

Tylko jako przykład (nie jestem pewien, że to pasuje do zadania):

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(); 

Powinieneś wiedzieć, że usługa działa w wątku UI, więc masz ten błąd. Sprawdź this nice site, aby uzyskać więcej informacji o różnych podejściach do wątków w systemie Android.