usar - Servicio de Android para mostrar tostadas
toast make in android (3)
Se supone que este código utiliza un servicio para mostrar un mensaje de brindis. No hay errores, pero no muestra la tostada.
actividad principal
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);
}
}
servicio (se llama música de fondo, pero por ahora se supone que muestra un mensaje de brindis)
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();
}
}
manifiesto
<?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>
Probablemente sea mejor delegar todas las actividades de la GUI (incluida la tostada) a la Actividad que utiliza su Servicio. Por ejemplo, tengo un servicio vinculado para realizar la captura de ubicación en segundo plano y publicar actualizaciones en la pantalla mientras mi aplicación está visible.
Mi aplicación implementa una interfaz simple:
public interface ICapture {
void update(Location location);
}
y mi clase def se ve así:
public class MyActivity extends Activity implements ICapture {
...
Aquí están las cosas para manejar el servicio vinculado:
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) {
}
};
Lo único aquí que no es estándar es la línea.
captureService.setOwner(ICapture.this);
que proporciona al servicio una referencia a la implementación de ICapture de la aplicación. Vea a continuación para saber cómo se utiliza.
Comienzo el servicio en onCreate ():
Intent intent = new Intent(this, CaptureService.class);
startService(intent);
bindService(intent, captureServiceConnection, Context.BIND_AUTO_CREATE);
y uso estos métodos para decirle al servicio cuando la aplicación está visible y puede satisfacer las solicitudes de 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);
}
}
El Servicio se ve así:
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;
}
}
}
Todo esto es un código bastante estándar que puedes encontrar en otros lugares. Lo principal es que cuando se produce una actualización de ubicación, el código llama a la aplicación a través de su interfaz ICapture implementada, pero solo si la aplicación está visible. La implementación de onPause () y onResume () en la aplicación asegura que el servicio sepa cuándo la aplicación puede aceptar llamadas.
Para hacer una ventana emergente de brindis, agregue otro método a la interfaz de ICapture e implementarlo en la aplicación. Su servicio puede llamarlo en cualquier momento en que sepa que la pantalla puede aceptarlo. De hecho, las ventanas emergentes de tostadas aún aparecerán incluso cuando la aplicación no esté en primer plano, pero creo que se bloquean cuando la pantalla se desactiva, lo que a su vez bloquea el servicio. Así que es mejor enviarlos solo cuando la aplicación está en primer plano.
Prueba esto:
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();
}
});
Ver esta parte de la documentación.
(Un IntentService tiene algunas limitaciones:
No puede interactuar directamente con su interfaz de usuario. Para poner sus resultados en la interfaz de usuario, debe enviarlos a una actividad.
Necesitas ponerlo en el Thread
principal. Vea la respuesta aquí por rony de una manera de hacer eso.
y de la documentación completa en IntentService
Maneja cada Intención a su vez usando un hilo de trabajo.