显示吐司的 Android 服务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21515917/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:41:54  来源:igfitidea点击:

Android Service to show toast

androidservicetoast

提问by codenamejupiterx

This code is supposed to use a service to show a toast message. There are no errors, but it doesn't show the toast.

此代码应该使用服务来显示 Toast 消息。没有错误,但它不显示吐司。

main activity

主要活动

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 (its called Background Music but for now it is supposed to show a toast message)

服务(它称为背景音乐,但现在它应该显示吐司消息)

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>

采纳答案by codeMagic

See this part of the docs

查看文档的这一部分

(An IntentService has a few limitations:

It can't interact directly with your user interface. To put its results in the UI, you have to send them to an Activity.

(一个 IntentService 有一些限制:

它不能直接与您的用户界面交互。要将其结果放在 UI 中,您必须将它们发送到 Activity。

You need to put it on the main Thread. See the answer here by ronyof a way to do that.

你需要把它放在 main 上Thread通过 rony的一种方法来查看这里的答案

and from the full documentation on IntentService

以及来自IntentService完整文档

handles each Intent in turn using a worker thread

使用工作线程依次处理每个 Intent

回答by Gal Rom

Try this:

尝试这个:

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

回答by Graham

It's probably best to delegate all GUI activities (including toast) to the Activity that is using your Service. For example, I have a bound service for doing location capture in the background and posting updates to the screen while my app is visible.

最好将所有 GUI 活动(包括 toast)委托给使用您的服务的活动。例如,我有一个绑定服务,用于在后台执行位置捕获并在我的应用程序可见时将更新发布到屏幕。

My app implements a simple interface:

我的应用程序实现了一个简单的界面:

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

and my class def looks like this:

我的类 def 如下所示:

public class MyActivity extends Activity implements ICapture {
...

Here's the stuff for handling the bound service:

这是处理绑定服务的内容:

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

The only thing here that's not standard is the line

这里唯一不标准的是线路

captureService.setOwner(ICapture.this);

which provides the service with a reference to the app's implementation of ICapture. See below for how it's used.

它为服务提供了对应用程序的 ICapture 实现的引用。请参阅下文了解它的使用方式。

I start the Service in onCreate():

我在 onCreate() 中启动服务:

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

and I use these methods to tell the service when the app is visible and able to satisfy GUI requests:

我使用这些方法告诉服务应用程序何时可见并能够满足 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);
    }
}

The Service looks like 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;
        }
    }
}

All this is pretty standard code you can find elsewhere. The main thing is that when a location update occurs the code calls the app via its implemented ICapture interface, but onlyif the app is visible. The implementation of onPause() and onResume() in the app makes sure that the service knows when the app can accept calls.

所有这些都是非常标准的代码,您可以在其他地方找到。最主要的是,当发生位置更新代码调用通过其实施的iCapture接口的应用程序,但只有当应用程序是可见的。应用程序中 onPause() 和 onResume() 的实现确保服务知道应用程序何时可以接受调用。

To do a toast popup, add another method to the ICapture interface and implement it in the app. Your service can then call it any time it knows the screen can accept it. In fact, toast popups will still come through even when the app isn't in the foreground, but I believe they get blocked when the screen goes inactive, which in turn blocks the service. So it's better to only send them when the app is in the foreground.

要执行 toast 弹出窗口,请向 ICapture 接口添加另一个方法并在应用程序中实现它。您的服务可以在知道屏幕可以接受它的任何时候调用它。事实上,即使应用程序不在前台,吐司弹出窗口仍然会出现,但我相信当屏幕处于非活动状态时它们会被阻止,从而阻止服务。所以最好只在应用程序处于前台时发送它们。