bindService android AIDL 总是 return false

bindService android AIDL always return false

我想提供一个可以被其他应用程序调用的服务。因此,我有一个服务和一个援助。但是当我尝试有一个单独的应用程序来绑定此服务 (bindService) 时,它只是 returns me false 这意味着失败。这是我的代码。

我正在使用 Pro 书中的代码 Android 2

我已经在其他类似的问题上尝试过很多解决方案,但没有适合我的解决方案。

我已尝试修复 aidl intent 过滤器,但它仍然无法正常工作

我已经尝试在客户端应用程序中修复程序包名称和 class 名称,但仍然无法正常工作。

请帮帮我!

在客户端:

// IStockQuoteService.aidl
package id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice;

// Declare any non-default types here with import statements

interface IStockQuoteService {
    double getQuote(String ticker);
}
package id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteclient;

import id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice.IStockQuoteService;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity {
    protected static final String TAG = "StockQuoteClient";
    private IStockQuoteService stockService = null;
    private Button bindBtn;
    private Button callBtn;
    private Button unbindBtn;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindBtn = (Button)findViewById(R.id.bindBtn);
        bindBtn.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setClassName("com.id.ac.ui.cs.mobileprogramming" +
                        ".ahmad_fauzan_amirul_isnain.stockquoteservice",
                        "com.id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain" +
                                ".stockquoteservice.IStockQuoteService");
                Log.d("Hasil", String.valueOf(bindService(intent,
                        serConn, Context.BIND_AUTO_CREATE)));
                bindBtn.setEnabled(false);
                callBtn.setEnabled(true);
                unbindBtn.setEnabled(true);
            }});
        callBtn = (Button)findViewById(R.id.callBtn);
        callBtn.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View view) {
                callService();
            }});
        callBtn.setEnabled(false);

        unbindBtn = (Button)findViewById(R.id.unbindBtn);
        unbindBtn.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View view) {
                unbindService(serConn);
                bindBtn.setEnabled(true);
                callBtn.setEnabled(false);
                unbindBtn.setEnabled(false);
            }});
        unbindBtn.setEnabled(false);
    }
    private void callService() {
        try {
            double val = stockService.getQuote("SYH");
            Toast.makeText(MainActivity.this, "Value from service is "+val,
                    Toast.LENGTH_SHORT).show();
        } catch (RemoteException ee) {
            Log.e("MainActivity", ee.getMessage(), ee);
        }
    }
    private ServiceConnection serConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            Log.v(TAG, "onServiceConnected() called");
            stockService = IStockQuoteService.Stub.asInterface(service);
            callService();
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.v(TAG, "onServiceDisconnected() called");
            stockService = null;
        }
    };
}

服务中:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice">

    <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="StockQuoteService">
            <intent-filter>
                <action android:name="com.id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice.IStockQuoteService"
                    />
            </intent-filter>
        </service>
    </application>

</manifest>
package id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class StockQuoteService extends Service
{
    private static final String TAG = "StockQuoteService";
    public class StockQuoteServiceImpl extends IStockQuoteService.Stub
    {
        @Override
        public double getQuote(String ticker) throws RemoteException
        {
            Log.v(TAG, "getQuote() called for " + ticker);
            return 20.0;
        }
    }
    @Override
    public void onCreate() {
        super.onCreate();
        Log.v(TAG, "onCreate() called");
    }
    @Override
    public void onDestroy()
    {
        super.onDestroy();
        Log.v(TAG, "onDestroy() called");
    }
    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Log.v(TAG, "onStart() called");
    }
    @Override
    public IBinder onBind(Intent intent)
    {
        Log.v(TAG, "onBind() called");
        return new StockQuoteServiceImpl();
    }
}
// IStockQuoteService.aidl
package id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice;

// Declare any non-default types here with import statements

interface IStockQuoteService {
    double getQuote(String ticker);
}

I'm using the code from books Pro Android 2

那本书是 2010 年的。那本书的大部分内容都已经过时了。请使用更新的东西。如果不出意外,您可以免费下载 older editions of one of my books。现在,这些最新版本是 2015 年的——虽然它也有点旧,但比 2010 年的书 更新。

I've already tried many solutions in other questions similar to this, but there isn't any working solution for me.

你有:

            intent.setClassName("com.id.ac.ui.cs.mobileprogramming" +
                    ".ahmad_fauzan_amirul_isnain.stockquoteservice",
                    "com.id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain" +
                            ".stockquoteservice.IStockQuoteService");

您清单中的 packageid.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice。假设模块 build.gradle 文件中的 applicationId 相同,我认为这与代码中的内容相匹配。你的应用ID很长,以后建议你用更短更容易直观比较的ID。

但是,您的 class 名字是错误的。你的 <service> class 是 StockQuoteService,而不是 IStockQuoteServiceIStockQuoteService 是 AIDL 的名称,而不是服务的名称,您的 Intent 需要指向服务。所以,试试:

            intent.setClassName("com.id.ac.ui.cs.mobileprogramming" +
                    ".ahmad_fauzan_amirul_isnain.stockquoteservice",
                    "com.id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain" +
                            ".stockquoteservice.StockQuoteService");

或者,为了减少重复:

            String packageName = "com.id.ac.ui.cs.mobileprogramming" +
                    ".ahmad_fauzan_amirul_isnain.stockquoteservice";
            intent.setClassName(packageName, packageName+".StockQuoteService");