Service Android pour montrer toast
ce code est censé utiliser un service pour afficher un message toast. Il n'y a pas d'erreurs, mais ça ne montre pas le toast.
activité principale
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 (son appelé musique de fond mais pour l'instant il est censé montrer un message toast)
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();
}
}
manifeste
<?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>
3 réponses
voir cette partie des documents
(un IntentService a quelques limitations:
Il ne peut pas interagir directement avec votre interface utilisateur. Pour mettre son résultats dans L'IU, vous devez les envoyer à une activité.
vous devez le mettre sur le main Thread
. Voir ici, la réponse par rony d'une façon de le faire.
et de la documentation complète sur IntentService
gère chaque intention à tour de rôle à l'aide d'un filetage ouvrier
essayez ceci:
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();
}
});
il est probablement préférable de déléguer toutes les activités de L'interface graphique (y compris toast) à l'activité qui utilise votre Service. Par exemple, j'ai un service lié pour faire la capture d'emplacement dans l'arrière-plan et l'affichage des mises à jour à l'écran pendant que mon application est visible.
mon application implémente une interface simple:
public interface ICapture {
void update(Location location);
}
et ma classe def ressemble à ceci:
public class MyActivity extends Activity implements ICapture {
...
voici le matériel pour gérer le service lié:
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) {
}
};
la seule chose ici qui n'est pas standard est la ligne
captureService.setOwner(ICapture.this);
qui fournit le service avec une référence à la mise en œuvre D'ICapture par l'app. Voir ci-dessous comment il est utilisé.
j'ai démarrer le Service dans onCreate():
Intent intent = new Intent(this, CaptureService.class);
startService(intent);
bindService(intent, captureServiceConnection, Context.BIND_AUTO_CREATE);
et j'utilise ces méthodes pour dire au service quand l'application est visible et capable de satisfaire les requêtes GUI:
@Override
public void onPause() {
super.onPause();
if (captureService != null) {
captureService.setOwner(null);
}
}
@Override
public void onResume() {
super.onResume();
if (captureService != null) {
captureService.setOwner(this);
}
}
Le Service ressemble à ceci:
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;
}
}
}
tout cela est assez code standard que vous pouvez trouver ailleurs. L'essentiel est que lorsqu'une mise à jour d'emplacement se produit le code appelle l'application via son interface ICapture implémentée, mais seulement si l'application est visible. L'implémentation d'onPause() et onResume() dans l'application permet de s'assurer que le service sait quand l'application peut accepter les appels.
pour faire un popup toast, ajouter une autre méthode à l'interface ICapture et l'implémenter dans l'application. Votre service peut ensuite l'appeler à tout moment, on sait que l'écran peut l'accepter. En fait, les popups toast vont toujours passer même lorsque l'application n'est pas au premier plan, mais je crois qu'ils sont bloqués lorsque l'écran devient inactif, ce qui à son tour bloque le service. Il est donc préférable d'envoyer uniquement lorsque l'application est au premier plan.