2017-07-19 2 views
0

Ich habe einen Dienst, der auf UDP-Pakete wartet, der an meine MainActivity gebunden ist (was die einzige Aktivität in der App ist). Der Dienst läuft auf einem eigenen Thread und ich kann die UDP-Nachrichten sowie die geparsten Nachrichten in logcat sehen. Ich habe eine setParsedMessage() und eine public getParsedMessage() erstellt, um die geparste Zeichenfolge zu erhalten und sie an meine Hauptaktivität zu senden, um eine TextView und eine ImageView abhängig von der geparsten Nachricht zu ändern, aber es scheint nicht die String für einige abrufen Grund. Ich lese über diese Methode auf der Developer.Android Website, aber ich habe auch etwas über die Verwendung von Handler, um dies stattdessen zu tun. Hier ist mein Code:Wie übergibt man einen String von einem UDP Listening Service an die MainActivity?

MainActivity:

public class MainActivity extends Activity { 

AlertAssignments mAlertAssignments; 



Button startListeningButton; 

boolean started; 
int counter; 
boolean mBound = false; 
Context context; 
ListenerService mListenerService; 

TextView mTextView; 
TextView mBlinkView; 
ImageView mImageView; 


private StartListening _StartListeningTask; 
String messageFromService = ""; 




@Override 
protected void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    //start listener service 
    Intent listenerServiceIntent = new Intent(MainActivity.this, ListenerService.class); 
    this.bindService(listenerServiceIntent, mConnection, Context.BIND_AUTO_CREATE); 

    mImageView = (ImageView) findViewById(R.id.image_view); 
    mTextView = (TextView) findViewById(R.id.alert_text); 
    mBlinkView = (TextView) findViewById(R.id.blinking_text); 
    Animation mAnimation = new AlphaAnimation(0.0f, 1.0f); 
    mAnimation.setDuration(50); 
    mAnimation.setStartOffset(20); 
    mAnimation.setRepeatCount(Animation.INFINITE); 
    mAnimation.setRepeatMode(Animation.REVERSE); 
    mBlinkView.startAnimation(mAnimation); //animation value 
    mAlertAssignments = new AlertAssignments(); 

} 
private ServiceConnection mConnection = new ServiceConnection() { 
    @Override 
    public void onServiceConnected(ComponentName className, IBinder service) { 
     ListenerService.LocalBinder binder = (ListenerService.LocalBinder) service; 
     mListenerService = binder.getService(); 
     mBound = true; 
     if(mBound) { 
      Log.e("UDP", "Service has been bound successfully"); 
     } 
     else { 
      Log.e("UDP", "Service has not been bound"); 
     } 

     readFromService(); 
    } 

    @Override 
    public void onServiceDisconnected(ComponentName name) { 
     mBound = false; 
    } 
}; 

@Override 
protected void onStart() { 
    super.onStart(); 

} 


@Override 
protected void onStop() { 
    super.onStop(); 
    //unbind from service 
    if(mBound) { 
     this.unbindService(mConnection); 
     mBound = false; 
    } 

} 

private void readFromService() { 
    try { 
     Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage()); 
     mImageView.setImageResource(mAlertAssignments.alarmImages[parsedMessage]); 

     if(parsedMessage >= 10 && parsedMessage <= 19 && parsedMessage != 0) { 
      mTextView.setText(mAlertAssignments.alertTextMessages[parsedMessage]); 
     } else { 
      mBlinkView.setText(mAlertAssignments.alertTextMessages[parsedMessage]); 
     } 
    } catch(NumberFormatException e) { 
     e.printStackTrace(); 
    } 

} 


} 

ich gelesen hatte, dass die öffentliche Getter wie folgt aus:
Integer parsedMessage = Integer.valueOf(mListenerService.getParsedMessage());
würde mir erlauben, den String-Wert von mListenerService.getParsedMessage zugreifen zu können, aber ich vermute, das funktioniert möglicherweise nur für gestartete Dienste, nicht für gebundene Dienste.

AlertAssignments ist eine einfache Enumeration, ordinal Arrays verwendet, um Bilder und Strings auf Werte zu binden, so mImageView.setImageResource(mAlertAssignments.alarmImages[parsedMessage]) die ImageView zu einem Bild festgelegt würde. Schließlich ist hier der Service:

public class ListenerService extends Service{ 
public String the_alarm_S; 
public String parsedMessage = ""; 
private final IBinder mBinder = new LocalBinder(); 


public class LocalBinder extends Binder { 
    ListenerService getService() { 
     return ListenerService.this; 
    } 
} 

@Override 
public IBinder onBind(Intent intent) { 
    return mBinder; 
} 

DatagramSocket socket; 

Thread UDPBroadcastThread; 

void startListenForUDPBroadcast() { 
    UDPBroadcastThread = new Thread(new Runnable() { 
     public void run() { 
      try { 
       while (shouldRestartSocketListen) { 
        try { 
         socket = new DatagramSocket(12001); 
         socket.setReuseAddress(true); 
         String message = ""; 

         byte[] recvBuf = new byte[1024]; 
         DatagramPacket packet = new DatagramPacket(recvBuf, 1024); 
         Log.e("UDP", "Waiting for UDP broadcast"); 
         try { 
          socket.receive(packet); 
          Log.e("UDP", "Received Packet"); 
         } catch (IOException e) { 
          e.printStackTrace(); 

         } 
         message = new String(packet.getData()); 

         Log.e("UDP", "Got UDB broadcast message: " + message); 

         setParsedMessage(message); 

         if(socket != null) { 
          socket.close(); 
         } 
        } catch (SocketException e) { 
         e.printStackTrace(); 
        } 
       } 
       //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; 

private void setParsedMessage(String messageContents) { 
    the_alarm_S = messageContents; 
    String parseMessage[] = the_alarm_S.split("!!!"); 
    Log.e("UDP", "Parsed message with value " + parseMessage[1]); 
    parsedMessage = parseMessage[1]; 

} 
public String getParsedMessage() { 
    return parsedMessage; 
} 

private void stopListen() { 
    shouldRestartSocketListen = false; 
    if(socket != null) { 
     socket.close(); 
    } 
} 

@Override 
public void onCreate() { 
    startListenForUDPBroadcast(); 
} 

@Override 
public void onDestroy() { 
    stopListen(); 
} 


@Override 
public int onStartCommand(Intent intent, int flags, int startId) { 
    shouldRestartSocketListen = true; 
    startListenForUDPBroadcast(); 
    Log.i("UDP", "Service started"); 
    return START_STICKY; 
} 
} 

Kann jemand geben Sie mir das einfachste Verfahren zur Herstellung der String aus dem Dienst an der Haupttätigkeit bekommen, oder wenn ich es schon, wo ich falsch es darin werde? Ich möchte vermeiden, dass meine Service als IntentService zu umschreiben, wenn es absolut notwendig ist, dies zu tun, da dies eine relativ einfache Aufgabe ist es, MainActivity

Dank

+0

Wie oft erhalten Sie die Nachricht? – vlatkozelka

+0

Werfen Sie einen Blick auf diese: https://stackoverflow.com/questions/28941513/how-to-pass-data-from-a-service-to-an-activity-in-android –

+0

@vlatkozelka: alle 1/100 von einer Sekunde Miha: der Dienst ist bereits gebunden. – Tadhg

Antwort

1

Sie versuchen, den Dienst abonnieren können. Was ich meine, ist eine Schnittstelle passieren, dass der Dienst die Aktivität über Änderungen zu informieren nennt, hier ist ein Beispiel, das ich gerade getestet:

Teilnehmerschnittstellen

public interface ServiceSubscriber { 
    void messageCallback(String message); 
} 

an den Dienst abonnieren Sie den Abonnenten

public class TestService extends Service { 

    ArrayList<ServiceSubscriber> subscribers = new ArrayList<>(); 
    private TestBinder testBinder = new TestBinder(); 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     new Thread(){ 
      @Override 
      public void run() { 
       while(true){ 
        //this is where you are receiving UDP packets 
        doStuff(); 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     }.start(); 
     return super.onStartCommand(intent, flags, startId); 
    } 

    @Nullable 
    @Override 
    public IBinder onBind(Intent intent) { 
     return testBinder; 
    } 

    private void doStuff() { 
     System.out.println("Service is doing stuff!"); 
     //loop through your subscribers and notify them of your changes 
     //a loop here isn't very costly, if there aren't many subscribers 
     for (ServiceSubscriber subscriber : subscribers) { 
      subscriber.messageCallback("I'm doing stuff"); 
     } 

    } 

    public class TestBinder extends Binder { 

     public TestService getService() { 
      return TestService.this; 
     } 
    } 

    public void subscribeToMessages(ServiceSubscriber subscriber) { 
     subscribers.add(subscriber); 
    } 


    public void unSubscribeToMessages(ServiceSubscriber subscriber) { 
     subscribers.remove(subscriber); 
    } 
} 
mit

Jetzt für die übliche Bindungsaktivität, wo Sie definieren, was Sie mit der Nachricht Rückruf tun müssen:

public class MainActivity extends AppCompatActivity { 
    private TestService testService; 
    private Subscriber subscriber; 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
    } 

    @Override 
    protected void onStart() { 
     super.onStart(); 

     bindService(new Intent(this, TestService.class),serviceConnection, Context.BIND_AUTO_CREATE); 
    } 

    private ServiceConnection serviceConnection = new ServiceConnection() { 
     @Override 
     public void onServiceConnected(ComponentName name, IBinder service) { 
      testService = ((TestService.TestBinder)service).getService(); 
      subscriber = new ServiceSubscriber() { 
       @Override 
       public void messageCallback(String message) { 
        //I'm just printing out the message received 
        //Be careful if you need to do UI stuff to use a 
        //Handler 
        System.out.println(message); 
       } 
      } 
      testService.subscribeToMessages(subscriber); 
     } 

     @Override 
     public void onServiceDisconnected(ComponentName name) { 

     } 
    }; 

} 

Natürlich vergessen Sie nicht, auf zerstören zu stornieren.

Aktualisierung UI oft bricht nicht Ihre App, wenn Sie es tun

einen Handler mithilfe von
//activity fields 
    Handler handler 



//in activity constructor 
handler = new Handler(); 

//update UI by calling 
handler.post(new Runnable(){ 
    @Override 
    public void run(){ 
    //update the UI here 
    } 

EDIT: Ich habe eine Referenz des Teilnehmers zu halten vergessen, später abmelden. Von anonymer Instanz in ein Feld geändert.

0

unten Methode, um Ihre sevice Klasse Stellen weitergeben müssen:

private void sendMessage() { 
    Intent intent = new Intent("message"); 
    intent.putExtra("message", your_message); 
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 
} 

Und setzen Sie den folgenden Code in Ihrer Aktivitätsklasse:

@Override 
public void onResume() { 
    super.onResume(); 

    LocalBroadcastManager.getInstance(this) 
         .registerReceiver(mMessageReceiver, 
             new IntentFilter("message")); 
} 

private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     String yourMessage = intent.getIntExtra("message",-1); 
    } 
}; 

@Override 
protected void onPause() { 
    LocalBroadcastManager.getInstance(this) 
         .unregisterReceiver(mMessageReceiver); 
    super.onPause(); 
} 

Hinweis: -1 ist für Standardwert

+0

Deshalb habe ich in Kommentaren gefragt, wie oft er die Nachricht erhält. Eine Sendung alle 1/100 wird nicht funktionieren. (Soweit ich weiß) – vlatkozelka

+0

Aktualisiert die Benutzeroberfläche, die oft ein Problem verursachen, oder sollte ich eine Delta-Funktion schreiben, die nur die Benutzeroberfläche ändert, wenn sich der Wert der Nachricht ändert? – Tadhg

+0

Ich denke, Sie sollten einen gebundenen Dienst verwenden, der es der Aktivität ermöglicht, einen direkten Verweis auf den Dienst zu erhalten und somit direkte Aufrufe zuzulassen, anstatt Intents zu verwenden. Wenn eine Nachricht vorliegt, können Sie die Benutzeroberfläche entsprechend aktualisieren. – huk

Verwandte Themen