it-swarm.com.de

Android Service, um Toast zu zeigen

Dieser Code soll einen Dienst verwenden, um eine Toastnachricht anzuzeigen. Es liegen keine Fehler vor, der Toast wird jedoch nicht angezeigt.

hauptaktivität

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Intent i= new Intent(this, BackgroundMusic.class);
    this.startService(i); 

}



}

service (es heißt Background Music, soll aber vorerst eine Toastnachricht anzeigen)

public class BackgroundMusic extends IntentService {

 public BackgroundMusic() {
      super("BackgroundMusic");
  }



 @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
     Context context = getApplicationContext();
     CharSequence text = "Hello toast!";
     int duration = Toast.LENGTH_SHORT;

     Toast toast = Toast.makeText(context, text, duration);
     toast.show();
 }



}

manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
package="com.example.starwars"
Android:versionCode="1"
Android:versionName="1.0" >

<uses-sdk
    Android:minSdkVersion="8"
    Android:targetSdkVersion="18" />

<application
    Android:allowBackup="true"
    Android:debuggable="true"
    Android:icon="@drawable/ic_launcher"
    Android:label="@string/app_name"
    Android:theme="@style/AppTheme" >
     <service Android:name=".BackgroundMusic" />
    <activity
        Android:name="com.example.starwars.MainActivity"
        Android:label="@string/app_name" >
        <intent-filter>
            <action Android:name="Android.intent.action.MAIN" />

            <category Android:name="Android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity Android:label="@string/app_name" Android:name="BackgroundMusic"/>
</application>

</manifest>
33

Siehe diesen Teil der Dokumentation

(Ein IntentService hat einige Einschränkungen:

Es kann nicht direkt mit Ihrer Benutzeroberfläche interagieren. Um die Ergebnisse in die Benutzeroberfläche zu übernehmen, müssen Sie sie an eine Aktivität senden.

Sie müssen es auf das Hauptverzeichnis Thread setzen. Siehe die Antwort hier von rony wie man das macht.

und aus der vollständige Dokumentation zu IntentService

behandelt jeden Intent der Reihe nach mit einem Worker-Thread

22
codeMagic

Versuche dies:

Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {

    @Override
    public void run() {
            Toast.makeText(YourService.this.getApplicationContext(),"My Awesome service toast...",Toast.LENGTH_SHORT).show();
            }
        });
75
Gal Rom

Es ist wahrscheinlich am besten, alle GUI-Aktivitäten (einschließlich Toast) an die Aktivität zu delegieren, die Ihren Service verwendet. Zum Beispiel habe ich einen gebundenen Dienst, um die Standorterfassung im Hintergrund durchzuführen und Updates auf dem Bildschirm zu veröffentlichen, während meine App sichtbar ist.

Meine App implementiert eine einfache Oberfläche:

public interface ICapture {
    void update(Location location);
}

und meine klasse def sieht so aus:

public class MyActivity extends Activity implements ICapture {
...

Hier ist das Zeug für die Abwicklung des gebundenen Dienstes:

private CaptureService captureService;
private ServiceConnection captureServiceConnection = new ServiceConnection() {

    public void onServiceConnected(ComponentName className, IBinder service) {
        CaptureService.MyLocalBinder binder = (CaptureService.MyLocalBinder) service;
        captureService = binder.getService();
        captureService.setOwner(ICapture.this);
    }

    public void onServiceDisconnected(ComponentName arg0) {
    }
};

Das einzige, was hier nicht zum Standard gehört, ist die Leitung

captureService.setOwner(ICapture.this);

hierdurch erhält der Dienst einen Verweis auf die Implementierung von ICapture durch die App. Siehe unten, wie es verwendet wird.

Ich starte den Dienst in onCreate ():

    Intent intent = new Intent(this, CaptureService.class);
    startService(intent);
    bindService(intent, captureServiceConnection, Context.BIND_AUTO_CREATE);

und ich benutze diese Methoden, um dem Dienst mitzuteilen, wann die App sichtbar ist und GUI-Anforderungen erfüllen kann:

@Override
public void onPause() {
    super.onPause();
    if (captureService != null) {
        captureService.setOwner(null);
    }
}

@Override
public void onResume() {
    super.onResume();
    if (captureService != null) {
        captureService.setOwner(this);
    }
}

Der Service sieht so aus:

package *****;

import Android.app.Service;
import Android.content.Intent;
import Android.location.Location;
import Android.os.Binder;
import Android.os.Bundle;
import Android.os.IBinder;

import com.google.Android.gms.common.ConnectionResult;
import com.google.Android.gms.common.GooglePlayServicesUtil;
import com.google.Android.gms.common.api.GoogleApiClient;
import com.google.Android.gms.location.LocationRequest;
import com.google.Android.gms.location.LocationServices;

public class CaptureService extends Service implements
        com.google.Android.gms.location.LocationListener,
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    private static final long UPDATE_INTERVAL = 1000 * 10;
    private static final long FASTEST_INTERVAL = 1000 * 5;

    private final IBinder myBinder = new MyLocalBinder();

    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;
    private ICapture owner;

    @Override
    public void onCreate() {
        if (isGooglePlayServicesAvailable()) {
            mGoogleApiClient = new GoogleApiClient.Builder(this)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .addApi(LocationServices.API)
                    .build();
            mLocationRequest = new LocationRequest();
            mLocationRequest.setInterval(UPDATE_INTERVAL);
            mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            mGoogleApiClient.connect();
        }
    }

    @Override
    public void onConnected(Bundle bundle) {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }

    @Override
    public void onConnectionSuspended(int i) {
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
    }

    /**************************************************************************
     * The binder that returns the service activity.
     */
    public class MyLocalBinder extends Binder {
        public CaptureService getService() {
            return CaptureService.this;
        }
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return myBinder;
    }

    /**************************************************************************
     * Bound methods.
     *
     * Set the owner, to be notified when the position changes.
     *
     * @param owner
     */
    public void setOwner(ICapture owner) {
        this.owner = owner;
    }

    /**************************************************************************
     * Start the service and keep it running when the phone is idle.
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    /**
     * Callback when the location changes. Inform the owner.
     *
     * @param location
     */
    @Override
    public void onLocationChanged(Location location) {
        if (owner != null) {
            owner.update(location);
        }
    }

    private boolean isGooglePlayServicesAvailable() {
        int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (ConnectionResult.SUCCESS == status) {
            return true;
        } else {
            return false;
        }
    }
}

All dies ist ziemlich normaler Code, den Sie woanders finden können. Die Hauptsache ist, dass bei einem Standort-Update der Code die App über die implementierte ICapture-Schnittstelle aufruft, aber nur wenn die App sichtbar ist. Durch die Implementierung von onPause () und onResume () in der App wird sichergestellt, dass der Dienst weiß, wann die App Anrufe annehmen kann.

Um ein Toast-Popup zu erstellen, fügen Sie der ICapture-Oberfläche eine andere Methode hinzu und implementieren Sie sie in der App. Ihr Dienst kann es dann jederzeit aufrufen, wenn er weiß, dass der Bildschirm es akzeptieren kann. Tatsächlich werden Toast-Popups auch dann angezeigt, wenn die App nicht im Vordergrund ist, aber ich glaube, dass sie blockiert werden, wenn der Bildschirm inaktiv wird, was wiederum den Dienst blockiert. Daher ist es besser, sie nur zu senden, wenn sich die App im Vordergrund befindet.

0
Graham