web-dev-qa-db-ja.com

Androidトーストを表示するサービス

このコードは、サービスを使用してトーストメッセージを表示することになっています。エラーはありませんが、トーストは表示されません。

主な活動

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

}



}

サービス(BGMと呼ばれますが、今のところはトーストメッセージを表示することになっています)

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



}

マニフェスト

<?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

ドキュメントのこの部分を参照

(IntentServiceにはいくつかの制限があります:

ユーザーインターフェイスと直接対話することはできません。結果をUIに配置するには、それらをアクティビティに送信する必要があります。

メインThreadに配置する必要があります。 ronyの回答 を参照してください。

および IntentServiceの完全なドキュメント

ワーカースレッドを使用して各Intentを順番に処理します

22
codeMagic

これを試して:

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

すべてのGUIアクティビティ(トーストを含む)を、サービスを使用しているアクティビティに委任することをお勧めします。たとえば、バックグラウンドで位置情報をキャプチャし、アプリが表示されている間に画面に更新を投稿するためのバインドされたサービスがあります。

私のアプリはシンプルなインターフェースを実装しています:

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

クラス定義は次のようになります。

public class MyActivity extends Activity implements ICapture {
...

バインドされたサービスを処理するためのものは次のとおりです。

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

ここで標準ではない唯一のものは、行です

captureService.setOwner(ICapture.this);

iCaptureのアプリの実装への参照をサービスに提供します。使用方法については、以下を参照してください。

OnCreate()でサービスを開始します。

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

そして、これらのメソッドを使用して、アプリが表示され、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);
    }
}

サービスは次のようになります。

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

これらはすべて、他の場所にあるかなり標準的なコードです。主なことは、場所の更新が発生すると、コードは実装されたICaptureインターフェイスを介してアプリを呼び出しますが、アプリが表示されている場合はonlyです。アプリでのonPause()およびonResume()の実装により、アプリがいつ通話を受け入れることができるかをサービスが確実に知ることができます。

トーストポップアップを実行するには、別のメソッドをICaptureインターフェイスに追加し、アプリに実装します。サービスは、画面がそれを受け入れることができるとわかっているときにいつでも呼び出すことができます。実際、トーストポップアップは、アプリがフォアグラウンドにない場合でも引き続き表示されますが、画面が非アクティブになるとブロックされ、サービスがブロックされます。そのため、アプリがフォアグラウンドにあるときにのみ送信することをお勧めします。

0
Graham