13

为了研究Android服务,我写了一个测试程序,屏幕上有“绑定服务”、“取消绑定服务”和“发送回显”三个按钮。单击时,它们使用bindService()unbindService()aMessenger与服务通信。

以下是服务代码:

public class MessengerService extends Service {

private final Messenger mMessenger = new Messenger(new TempHandler());
private class TempHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MSG_SAY_HELLO:
            Toast.makeText(getApplicationContext(), "Hi, there.", Toast.LENGTH_SHORT).show();
            break;

        case MSG_SAY_GOODBYE:
            Toast.makeText(getApplicationContext(), "See you next time.", Toast.LENGTH_SHORT).show();
            break;

        case MSG_ECHO:
            Toast.makeText(getApplicationContext(), "Received " + msg.arg1 + " from client.", Toast.LENGTH_SHORT).show();

            Messenger replyMessenger = msg.replyTo;
            Message replyMsg = Message.obtain(null, MSG_ECHO, msg.arg1, 0);
            try {
                replyMessenger.send(replyMsg);
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        default:
            super.handleMessage(msg);
        }
    }

}

@Override
public IBinder onBind(Intent intent) {
    Toast.makeText(getApplicationContext(), "Service bound", Toast.LENGTH_SHORT).show();
    return mMessenger.getBinder();
}

@Override
public void onDestroy() {
    Log.d("", "Service.onDestroy()...");
    super.onDestroy();
}
}

这是活动代码:

public class MessengerActivity extends Activity {
private Messenger mMessengerService;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity2);

    Button bind = (Button) findViewById(R.id.button5);
    bind.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            doBindService();
        }           
    });

    Button unbind = (Button) findViewById(R.id.button6);
    unbind.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            doUnbindService();
        }
    });

    Button echo = (Button) findViewById(R.id.button7);
    echo.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            doSendEcho();
        }
    });
}

private void doBindService() {
    Intent intent = new Intent(getApplicationContext(), MessengerService.class);
    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}

private void doUnbindService() {
    Message msg = Message.obtain(null, MessengerService.MSG_SAY_GOODBYE);
    try {
        mMessengerService.send(msg);
    } catch (RemoteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    unbindService(mConnection);     
}

private void doSendEcho() {
    if (mMessengerService != null) {
        Message msg = Message.obtain(null, MessengerService.MSG_ECHO, 12345, 0);
        msg.replyTo = mMessenger;
        try {
            mMessengerService.send(msg);
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

private final Messenger mMessenger = new Messenger(new TempHandler());
private ServiceConnection mConnection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Toast.makeText(getApplicationContext(), "Service is connected.", Toast.LENGTH_SHORT).show();

        mMessengerService = new Messenger(service);

        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO);
        try {
            mMessengerService.send(msg);
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mMessengerService = null;
        Toast.makeText(getApplicationContext(), "Service is disconnected.", Toast.LENGTH_SHORT).show();
    }

};

private class TempHandler extends Handler {

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MessengerService.MSG_ECHO:
            Toast.makeText(getApplicationContext(), "Get the echo message (" + msg.arg1 + ")", Toast.LENGTH_SHORT).show();
            break;

        default:
            super.handleMessage(msg);
        }
    }

}
}

当我单击“绑定服务”和“发送回显”按钮时。我可以看到服务已连接并且消息通信良好。然后单击“取消绑定服务”,我看到服务onDestroy()被调用,所以我希望服务停止并且不应该再次响应即将到来的消息。但实际上,该服务似乎还活着,当单击“发送回声”按钮时,我可以再次收到回声消息。所以我想知道我做错了什么吗?或者也许我对这项服务并不完全了解?

希望有人能帮忙,谢谢。

4

5 回答 5

4

当应用程序组件通过调用绑定到服务时,服务被“绑定” bindService()。绑定服务提供了一个客户端-服务器接口,允许组件与服务交互、发送请求、获取结果,甚至通过进程间通信 (IPC) 跨进程执行此操作。绑定服务仅在另一个应用程序组件绑定到它时运行

http://developer.android.com/guide/components/services.html

bindService()在所有调用都有相应的调用后,服务将关闭unbindService()。如果没有绑定的客户端,那么当且仅当有人在服务上调用 startService() 时,服务也需要 stopService()。

从以下链接绘制。

如何检查服务是否在 Android 上运行?.

private void doSendEcho() {
    if(isMyServiceRunning()) // if service is running
    {
    if (mMessengerService != null) {
        Message msg = Message.obtain(null, MessengerService.MSG_ECHO, 12345, 0);
        msg.replyTo = mMessenger;
        try {
            mMessengerService.send(msg);
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    }
}
private boolean isMyServiceRunning() {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (MessengerService.class.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

@Override
protected void onStop() {
super.onStop();
// Unbind from the service
    unbindService(mConnection);
    Log.i("Stopped!",""+isMyServiceRunning()); 
    Log.i("stopped", "Service Stopped");    
 }

例子:

我测试了下面它工作正常。

public class MessengerService extends Service {

    public static final int MSG_SAY_HELLO =1;
    public static final int MSG_SAY_GOODBYE =2;

      ArrayList<Messenger> mClients = new ArrayList<Messenger>();

private final Messenger mMessenger = new Messenger(new TempHandler());
private class TempHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MSG_SAY_HELLO:
            mClients.add(msg.replyTo);
            Toast.makeText(getApplicationContext(), "Hi, there.", Toast.LENGTH_SHORT).show();
            break;

        case MSG_SAY_GOODBYE:
            mClients.add(msg.replyTo);

            break;

        default:
            super.handleMessage(msg);
        }
    }

}

@Override
public IBinder onBind(Intent intent) {
    Toast.makeText(getApplicationContext(), "Service bound", Toast.LENGTH_SHORT).show();
    return mMessenger.getBinder();
}

@Override
public void onDestroy() {
    Log.i("MessengerService", "Service Destroyed...");
    super.onDestroy();
}
}

MainAactivity.java

public class MainActivity extends Activity {

boolean mIsBound=false;
Messenger mService = null;
private boolean isMyServiceRunning() {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (MessengerService.class.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button bind = (Button) findViewById(R.id.button1);
    bind.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            doBindService();
        }           
    });

    Button unbind = (Button) findViewById(R.id.button2);
    unbind.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            doUnbindService();
        }
    });
}

class TempHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MessengerService.MSG_SAY_GOODBYE:
                Toast.makeText(MainActivity.this,"Received from service: " + msg.arg1,1000).show();
                break;
            default:
                super.handleMessage(msg);
        }
    }
}

/**
 * Target we publish for clients to send messages to IncomingHandler.
 */
final Messenger mMessenger = new Messenger(new TempHandler());

/**
 * Class for interacting with the main interface of the service.
 */
private ServiceConnection mConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className,
            IBinder service) {
        // This is called when the connection with the service has been
        // established, giving us the service object we can use to
        // interact with the service.  We are communicating with our
        // service through an IDL interface, so get a client-side
        // representation of that from the raw service object.
        mService = new Messenger(service);
      //  mCallbackText.setText("Attached.");

        // We want to monitor the service for as long as we are
        // connected to it.
        try {
            Message msg = Message.obtain(null,
                    MessengerService.MSG_SAY_HELLO);
            msg.replyTo = mMessenger;
            mService.send(msg);

            // Give it some value as an example.
//            msg = Message.obtain(null,
//                    MessengerService.MSG_E, this.hashCode(), 0);
//            mService.send(msg);
        } catch (RemoteException e) {
            // In this case the service has crashed before we could even
            // do anything with it; we can count on soon being
            // disconnected (and then reconnected if it can be restarted)
            // so there is no need to do anything here.
        }

        // As part of the sample, tell the user what happened.
        Toast.makeText(MainActivity.this, "remote_service_connected",
                Toast.LENGTH_SHORT).show();
    }

    public void onServiceDisconnected(ComponentName className) {
        // This is called when the connection with the service has been
        // unexpectedly disconnected -- that is, its process crashed.
        mService = null;
       // mCallbackText.setText("Disconnected.");

        // As part of the sample, tell the" user what happened.
        Toast.makeText(MainActivity.this, "remote_service_disconnected",
                Toast.LENGTH_SHORT).show();
    }
};



void doBindService() {
    // Establish a connection with the service.  We use an explicit
    // class name because there is no reason to be able to let other
    // applications replace our component.
    bindService(new Intent(MainActivity.this, 
            MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
    mIsBound=true;
    Toast.makeText(MainActivity.this, "Binding",1000).show();
}

void doUnbindService() {
    if (mIsBound) {
        // If we have received the service, and hence registered with
        // it, then now is the time to unregister.
        if (mService != null) {
            try {
                Message msg = Message.obtain(null,
                        MessengerService.MSG_SAY_GOODBYE);
                msg.replyTo = mMessenger;
                mService.send(msg);
            } catch (RemoteException e) {
                // There is nothing special we need to do if the service
                // has crashed.
            }
        }

        // Detach our existing connection.
        unbindService(mConnection);
        mIsBound = false;
       Toast.makeText(MainActivity.this, "UnBinding"+isMyServiceRunning(),1000).show();

    }
}
}
于 2013-06-29T10:45:00.060 回答
3

我个人认为术语/命名法令人不满意/具有误导性。如果将“onDestroy”和“stopService”分别称为“FlagForAndroidOSDestruction”和“FlagForAndroidStopService”,可能会更好理解。

如果下载/编译/运行以下任一示例,可以看到即使 OnHandleIntent 完成或调用了 stopService,进程甚至服务仍然可以挂起!要查看这一点,只需启动下面的示例,然后在您的手机/平板电脑上转到 Settings->Apps->Running->Show Running Services and Settings->Apps->Running->Show Cached Processes

当您看到这些时,请尝试在手机上启动大量其他应用程序,然后您会看到 Android 破坏了上述服务和进程。

http://developer.android.com/guide/components/services.html#ExtendingIntentService

http://android-er.blogspot.com/2013/03/stop-intentservice.html

如何检查android中所有正在运行的服务?

于 2015-01-08T18:39:53.177 回答
1

是的,这是从官方文档中得出的结论:

服务既可以启动,也可以绑定连接。在这种情况下,只要服务已启动或有一个或多个使用 Context.BIND_AUTO_CREATE 标志的连接,系统就会保持服务运行。一旦这两种情况都不成立,服务的 onDestroy() 方法就会被调用并且服务被有效地终止。从 onDestroy() 返回时,所有清理(停止线程、注销接收器)都应该完成。

于 2015-02-26T15:24:46.177 回答
0

http://developer.android.com/guide/components/services.html

这两条路径并不完全分开。也就是说,您可以绑定到已经使用 startService() 启动的服务。例如,可以通过使用标识要播放的音乐的 Intent 调用 startService() 来启动背景音乐服务。稍后,可能当用户想要对播放器进行一些控制或获取有关当前歌曲的信息时,活动可以通过调用 bindService() 绑定到服务。在这种情况下,stopService() 或 stopSelf() 不会真正停止服务,直到所有客户端解除绑定。

所以你必须在 stopService() 之后调用 unBindService()

于 2013-06-29T10:27:50.330 回答
-1

此链接(我需要为 Android 服务调用 unbindService 和 stopService 吗?)说您需要在 unbindService 之前调用 stopService。

试试看。

于 2013-06-29T09:47:46.053 回答