bindService принудительно закрывается - PullRequest
2 голосов
/ 12 августа 2011

Я довольно новичок в программировании на Android и на Java в целом, но у меня большой опыт работы в качестве программиста на уровне C.Я хотел создать API или библиотеку, которая могла бы использоваться набором приложений для Android, которые я планирую разработать, и после долгих исследований я решил, что привязанный сервис - это способ Android (я бы обычно создавал .soили .dll).Если это предположение неверно, тогда весь мой вопрос вполне может быть спорным.

Во всяком случае, я создал каркас своего сервиса в одном проекте и создал действие в другом для тестирования сервиса.Я заглушил метод handleMessage () службы с помощью вызовов Toast, чтобы посмотреть, работает ли он, а затем добавил в свою деятельность две кнопки: одну для привязки службы и вторую для ее отмены.После часа неспособности выполнить свою деятельность, потому что она не видела мой сервис, я понял, как заставить Eclipse видеть исходный код сервиса из действия, и подумал, что у меня все в порядке.Потом я запустил игру.

Все выглядело хорошо.Две кнопки, одна для привязки, другая для отмены.Однако, когда я нажал кнопку привязки, приложение принудительно закрылось.Я использовал отладчик, чтобы увидеть, что происходит, и это принудительное закрытие вызова bindService () в моей деятельности.Конечно, вызов bindService () был скопирован из другого примера, в котором в той же строке был создан новый Intent (), поэтому я разделил две строки кода, и он действительно умирает при попыткедля создания намерения.

Вот код моей деятельности:

package net.william.android.myAPI.tester;

import net.william.android.myAPI.MyApiService;
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.view.View;
import android.widget.Toast;

public class MyApiTester extends Activity
{
    boolean mIsBound = false;

    private ServiceConnection mConnection = new ServiceConnection()
    {
        public void onServiceConnected(ComponentName className, IBinder service)
        {
            Toast.makeText(FaceClientTester.this, "Remote Service Connected", Toast.LENGTH_SHORT).show();
        }

        public void onServiceDisconnected(ComponentName className)
        {
            Toast.makeText(FaceClientTester.this, "Remote Service Disconnected", Toast.LENGTH_SHORT).show();
        }
    };

    public void doBindService(View view)
    {
        if (!mIsBound)
        {
            Toast.makeText(this, "Binding Service", Toast.LENGTH_SHORT).show();
            Intent myIntent = new Intent(MyApiTester.this, MyApiService.class); 
            bindService(myIntent, mConnection, Context.BIND_AUTO_CREATE);
            mIsBound = true;
        }
    }

    public void doUnbindService(View view)
    {
        if (mIsBound)
        {
            unbindService(mConnection);
            mIsBound = false;
            Toast.makeText(this, "Service Unbound", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        return;
    }
}

Это код моего сервиса:

package net.william.android.myAPI

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.widget.Toast;

public class MyApiService extends Service
{
    static final int API_FN_1   = 101;
    static final int API_FN_2   = 102;

    class MyApiHandler extends Handler
    {
        @Override
        public void handleMessage(Message msg)
        {
            switch (msg.what)
            {
                case API_FN_1:
                    ApiFn1();
                    break;
                case API_FN_2:
                    ApiFn2();
                    break;
                default:
                    super.handleMessage(msg);
                    break;
            }
        }
    }

    final Messenger myMessenger = new Messenger(new MyApiHandler());

    @Override
    public void onCreate()
    {
        Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDestroy()
    {
        Toast.makeText(this, "Service Stopped", Toast.LENGTH_SHORT).show();
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        Toast.makeText(this, "Service Bound", Toast.LENGTH_SHORT).show();
        return myMessenger.getBinder();
    }

    private void ApiFn1()
    {
        Toast.makeText(this, "API Function 1", Toast.LENGTH_SHORT).show();
        return;
    }

    private void ApiFn2()
    {
        Toast.makeText(this, "API Function 2", Toast.LENGTH_SHORT).show();
        return;
    }
}

Я изменил некоторые изназвания вещей, но это действительно основа моего кода.Просто несколько звонков в Toast, чтобы я мог надеяться увидеть, что все работает.

Все учебники, которые я нашел по этому вопросу, полностью проигнорировали манифест.Прошлой ночью я немного ковырялся, пытаясь настроить манифесты, думая, что это как-то связано с этим, но безрезультатно.Во всяком случае, для полноты ниже приведен код манифеста для действия:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.william.android.myAPI.tester"
    android:versionCode="1"
    android:versionName="1.0">
    <uses-sdk android:minSdkVersion="10" />
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MyApiTester" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

и службы:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.william.android.myAPI"
    android:versionCode="1"
    android:versionName="1.0">
    <uses-sdk android:minSdkVersion="10" />
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <service android:name=".MyApiService"></service>
    </application>
</manifest>

Я попытался добавить следующее внутри <service>заблокировать, но, похоже, это не помогло:

            <intent-filter>
                <action android:name="net.william.android.myAPI.MyApiService" />
            </intent-filter>

В любом случае, это мой первый пост на вашем форуме, поэтому я прошу прощения, если есть слишком много или слишком мало информации, или я действительно пропустил некоторыелегко исправить там где-то в сети.Я не спал большую часть ночи, читая всю документацию по сервисам, которая была у Google, и читая пост за постом на форумах, поэтому в этот момент я мог легко что-то упустить.Заранее спасибо всем, кто найдет время помочь!

1 Ответ

1 голос
/ 12 августа 2011

Если они должны распространяться в виде двух отдельных файлов APK, как указано в вашей паре манифестов, вы не можете использовать конструктор Intent, который принимает класс Java в качестве параметра. Тот факт, что он даже компилируется, указывает на то, что настройки вашего проекта несколько пугающие - ваш клиент не должен находиться в пределах мили страны от вашего сервиса с точки зрения времени сборки.

Добавьте <intent-filter> к вашей <service> рекламе, к которой вы хотите подключиться, и используйте эту структуру в своем клиенте для Intent, которую он создает.

Например, в этой паре образца проектов служба имеет:

<service android:name=".BshService">
    <intent-filter>
        <action android:name="com.commonsware.android.advservice.IScript" />
    </intent-filter>
</service>

и поэтому клиент использует:

new Intent("com.commonsware.android.advservice.IScript")
...