13

Androidのサービスを勉強するために、画面上に「サービスのバインド」「サービスのバインド解除」「エコー送信」の3つのボタンを表示するテストプログラムを作成しました。クリックするとbindService()unbindService()とを使用Messengerしてサービスと通信します。

サービスコードは次のとおりです。

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 に答える
1

はい、これは公式ドキュメントから引き出された結論です:

サービスは、開始することも、接続をバインドすることもできます。このような場合、サービスが開始されているか、Context.BIND_AUTO_CREATE フラグを使用してサービスへの接続が 1 つ以上ある限り、システムはサービスを実行し続けます。これらの状況のいずれにも当てはまらない場合、サービスの onDestroy() メソッドが呼び出され、サービスは事実上終了します。すべてのクリーンアップ (スレッドの停止、レシーバーの登録解除) は、onDestroy() から戻るときに完了する必要があります。

于 2015-02-26T15:24:46.177 に答える
-1

このリンク ( Do I need to call both unbindService and stopService for Android services? ) は、unbindService の前に stopService を呼び出す必要があることを示しています。

それを試してみてください。

于 2013-06-29T09:47:46.053 に答える