首页 > 解决方案 > Not able to connect with a Service

问题描述

I'm trying to create a service that handles networking in my app. I followed all the steps in https://developer.android.com/reference/android/app/Service and https://developer.android.com/guide/components/bound-services#Binding, but the activity doesn't seem to connect with the service.

Here is the SocketService, which has the TcpClient object that connects to my server using sockets:

public class SocketService extends Service{

    TcpClient tcpClient = new TcpClient();

    private final IBinder mBinder = new LocalBinder();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        SocketService getService() {
            // Return this instance of LocalService so clients can call public methods
            return SocketService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    /*
    * Client methods
    */

    public void connect(MyCallback callback, String ip, int port){
        tcpClient.connect(callback, ip, port);
    }

    public String disconnect(){
        return tcpClient.disconnect();
    }

    public String send(String data){
        return tcpClient.send(data);
    }

    public String recv(){
        return tcpClient.recv();
    }
}

Here is my main activity:

public class MainActivity extends AppCompatActivity {

    SocketService socketService;
    boolean bound = false;

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

    @Override
    protected void onStart(){
        super.onStart();

        Intent serviceIntent = new Intent(MainActivity.this, SocketService.class);

        if(bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)){
            Toast.makeText(getApplicationContext(), "bound", Toast.LENGTH_LONG);
        }

        if(bound) {
            socketService.connect(this, ip, port);
        } else {
            Toast.makeText(getApplicationContext(), "not bond", Toast.LENGTH_LONG).show();
        }
    }

    /*
    * Service callback
    */
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                                   IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            Toast.makeText(getApplicationContext(), "ServiceConnection", Toast.LENGTH_LONG);
            socketService = ((SocketService.LocalBinder) service).getService();
            bound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            socketService = null;
            bound = false;
        }
    };
}

And the AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.drrbarrera.home">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".SocketService"
            android:enabled="true"
            android:exported="true">
        </service>
    </application>

</manifest>

As I said before, the MainActivity doesn't seem to connect. "socketService" (in the MainActivity) stays null and "bound" stays false, like if "mConnection" wasn't being executed. Any idea of what might be wrong? Any help is appreciated. Thanks in advance!

标签: javaandroid

解决方案


调用bindService()返回一个布尔结果,告诉您绑定是否成功(实际上,这意味着正在进行中)。该操作是异步的,即使在同一个进程中(这就是你LocalBinder的。)

换句话说,在你ServiceConnection.onServiceConnected()被回调之前,绑定是不完整的。一旦该回调被触发并且您获得了服务绑定器,您就可以调用支持服务。

其他一些可以帮助您的注意事项:

  • 由于您Service与您在同一进程中运行Activity,因此调用是直接的并且不使用活页夹线程。这将对您的Activity代码产生影响。
  • 阻塞调用不应该是主 (UI) 线程上的主线程。这意味着如果您的Activity代码要调用socketService.connect(),则需要从后台线程执行此操作。否则,您将收到异常,因为 Android 现在会阻止主线程上的网络 I/O。其他类型的阻塞操作可能会导致 ANR,这将导致您的应用程序崩溃。
  • 如果您的网络 I/O 用于 REST 或其他与 HTTP 相关的流量,请考虑使用 Retrofit 或 Volley,因为它们具有高性能、可扩展性,并且可以为您处理与网络和 HTTP 相关的繁重工作。

推荐阅读