Невозможно вызвать метод Bluetooth BroadcastReceiver в службе

У меня такой класс обслуживания:

 public class BluetoothService extends Service {

    private static Activity mActivity;

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

    @Override
    public void onCreate() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        this.registerReceiver(bluetoothReceiver, intentFilter);     
    }

    @Override
    public void onDestroy() {
        if (bluetoothReceiver != null) {
            this.unregisterReceiver(bluetoothReceiver);
        }       
    }

    @Override
    public void onStart(Intent intent, int startid) {
           //
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {        
        return START_STICKY;
    }

    public static BroadcastReceiver bluetoothReceiver = new BroadcastReceiver(){
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
                TextView tvStatus = (TextView) mActivity.findViewById(R.id.tvtatus);
                Messaging.appendMessage(tvStatus, Bluetooth.getDeviceState(state));
                if (Bluetooth.isBluetoothEnabled()) {
                    Messaging.appendMessage(tvStatus, Bluetooth.showMessage());
                }               
            }
        }
    };  
}

И в моем классе Activity у меня есть следующее:

public class MainActivity extends Activity {

    private TextView tvStatus;
    private Intent intentBluetooth;

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

       tvStatus = (TextView)findViewById(R.id.tvtatus);

       intentBluetooth = new Intent(this, BluetoothService.class);
       startService(intentBluetooth);
    }
}

Метод BroadcastReceiver (bluetoothReceiver) в классе Service никогда не вызывается. Не знаю почему. Если у меня есть коды IntentFilter и BroadcastReceiver, прежде всего в Activity, то он работает, но не в [отдельной] службе. Я в тупике.

Мой AndroidManifest.xml:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.onegoal.androidexample"
        android:versionCode="1"
        android:versionName="1.0.0" 
        android:installLocation="auto"
        android:hardwareAccelerated="true">

        <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15" />

        <uses-permission android:name="android.permission.BLUETOOTH" />
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
        <uses-feature android:name="android.hardware.bluetooth" android:required="false" /> 

        <application
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" 
            android:debuggable="true" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name"
                android:theme="@android:style/Theme.NoTitleBar" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <service android:name=".BluetoothService">
            </service>
        </application>  
    </manifest>

Я новичок в Android, поэтому то, что я делаю, может быть не самым лучшим. Надеюсь, кто-нибудь может мне помочь.


person ChuongPham    schedule 03.08.2012    source источник
comment
Вы дали разрешение Bluetooth в AndroidManifest.xml?   -  person Lucifer    schedule 03.08.2012
comment
Да, у меня есть эти разрешения в AndroidManifest.xml: ‹uses-permission android: name = android.permission.BLUETOOTH /› ‹uses-permission android: name = android.permission.BLUETOOTH_ADMIN /›   -  person ChuongPham    schedule 03.08.2012
comment
зарегистрировать получателя в манифесте, и, как сказал @Lucifer, вы приняли разрешение ?? Даже я не думаю, что вы можете сделать TextView tvStatus = (TextView) mActivity.findViewById (R.id.tvtatus); в приемнике ур ..?   -  person AAnkit    schedule 03.08.2012


Ответы (1)


возможно, проблема связана с тем, что ваш приемник статичен.

BroadcastReceiver никогда не должен быть статичным. это может вызвать множество проблем.

другая действительно плохая проблема дизайна с вашим кодом - держать ссылку на активность внутри службы и использовать ее для изменения представлений действительно неправильно. это может легко вызвать утечку памяти. Правильно, почему общаться между Service и Activity - это реализовать Messanger андроида или посылать широковещательные сообщения между ними через BroadcastReceiver.

если вы прислушаетесь к моему совету - вам не придется делать свой приемник статическим (я думаю, вы сделали его статическим только потому, что вы используете статический экземпляр mActivity внутри), и я почти уверен, что это решит вашу проблему. проблема

вы можете прочитать о Messanger здесь: http://developer.android.com/reference/android/os/Messenger.html

конечно, вы найдете множество примеров использования в сети.

пример трансляции обновлений активности из сервиса:

public class MyService extends Service {

@Override
public IBinder onBind(Intent arg0) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public void onCreate() {
    super.onCreate();

    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
    this.registerReceiver(bluetoothReceiver, intentFilter);
}

@Override
public void onDestroy() {
    if (bluetoothReceiver != null) {
        this.unregisterReceiver(bluetoothReceiver);
    }
    super.onDestroy();
}

public BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
            final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
            updateUIWithNewState(state);
        }
    }
};

protected void updateUIWithNewState(int state) {
    Intent intent = new Intent("serviceUpdateReceivedAction");
    intent.putExtra("state", state);
    sendBroadcast(intent);
}

}

и это действие:

public class MyActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Intent intent = new Intent(this, MyService.class);
    startService(intent);
}

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

    registerReceiver(mServiceUpdatesReceiver, new IntentFilter("serviceUpdateReceivedAction"));
}

@Override
protected void onPause() {
    unregisterReceiver(mServiceUpdatesReceiver);
    super.onPause();
}

private BroadcastReceiver mServiceUpdatesReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        int state = intent.getIntExtra("state", -1);
        // do what ever you want in the UI according to the state
    }
};
}
person Tal Kanel    schedule 03.08.2012
comment
Делать приемник нестатичным - нет никакой разницы. Я видел класс Messenger раньше, но не могу найти способ, которым этот класс может отправлять прогрессивные обновленные сообщения, полученные от BroadcastReceiver, для такого намерения, как BluetoothAdapter.EXTRA_STATE. - person ChuongPham; 03.08.2012
comment
@Chuong: Я не хочу спорить о том, возможно это или нет. Если все, что делает ваш приемник, - это текст настроек в textView, зачем вам эта услуга? это классическая причина для реализации приемника внутри активности - person Tal Kanel; 03.08.2012
comment
Я с тобой не спорю. Я просто говорю, что пока не могу найти способ использовать класс Messenger (потому что не знаю как). Это все. Надеюсь, это устранит недоразумения - person ChuongPham; 03.08.2012
comment
@Chuong: подождите секунду, я напишу вам минутный пример из моего собственного проекта. Я использую Messanger. - person Tal Kanel; 03.08.2012
comment
@Chuong: знаешь что? - Думаю, вам лучше использовать трансляции. вам необходимо зарегистрировать свою активность в какой-либо трансляции, которую будет отправлять ваш сервис. это второй вариант, который я предложил в своем ответе. вам нужен пример, как это сделать? в любом случае - это хороший пример, который я нашел: websmithing.com/2011/02/01/ - person Tal Kanel; 03.08.2012
comment
Да, если вы можете показать мне пример. Я был бы очень признателен. - person ChuongPham; 03.08.2012
comment
Спасибо, Таль. Позвольте мне попробовать реализовать ваши коды, и я вернусь к вам после встречи. - person ChuongPham; 03.08.2012
comment
Tal: Я пробовал ваши коды, но ни метод bluetoothReceiver в классе Service, ни метод mServiceUpdatesReceiver в классе Activity не сработали. Я поместил несколько отладочных кодов, включая команду Toast, но ни один из них не был вызван. Ты знаешь почему? - person ChuongPham; 03.08.2012
comment
@Chuong: вы уверены, что был вызван метод onCreate () вашей службы? вы заявили о своей услуге в манифесте? - person Tal Kanel; 03.08.2012
comment
У меня это объявлено в манифесте: ‹service android: name = com.onegoal.service.BluetoothService /›. Об этом заявлено в группе ‹application›. - person ChuongPham; 03.08.2012
comment
@Chuong: вы точно знали, что сервис запущен? (вызывается метод onCreate службы) - person Tal Kanel; 03.08.2012
comment
\ @Tal: Да, звонят, но дело обстоит именно так. - person ChuongPham; 03.08.2012
comment
@Chuong: если это так. Я действительно не понимаю, почему это не работает. - person Tal Kanel; 03.08.2012
comment
Я только что повторно объявил службу как ‹service android: name = .BluetoothService /›, и кажется, что вызываются все методы класса BluetoothService. Но метод mServiceUpdatesReceiver в Activity не вызывается. Это очень странно. Нужно ли мне также объявить этот метод BroadcastReceiver в манифесте? Я не думал, что должен. - person ChuongPham; 03.08.2012
comment
@Chuong: нет, вам не нужно объявлять это в манифесте. убедитесь, что вы используете ту же строку действия (в моем примере она называется - serviceUpdateReceivedAction), но поскольку я зарегистрировал приемник внутри onResume () и отменил регистрацию внутри onPuase - тогда, когда действие не является открытым (или экран устройства близко) трансляция не принимается - person Tal Kanel; 03.08.2012
comment
@@ Tal: Как же тогда предложить мне обойти проблему переднего плана активности? Намек есть? ... - person ChuongPham; 03.08.2012
comment
@Chuong: если это причина, по которой он не работает, то решение простое - вместо регистрации получателя внутри onResume - зарегистрируйте его в onCreate. вместо того, чтобы отменить регистрацию внутри onPuase - отмените регистрацию внутри onDestroy. - person Tal Kanel; 03.08.2012
comment
Я тоже пробовал, тот же результат, метод onReceive в Activity никогда не вызывается. Я видел в файле журнала, что методы onCreate, onPause и onDestroy вызываются в действии, но не onReceive. Я действительно в тупике. Я даже искал в Google решения для переднего плана деятельности, пробовал их, но они не работают (возможно, я не полностью понимаю представленные решения) ... - person ChuongPham; 03.08.2012
comment
@Chuong: единственное, что я могу сделать, это увидеть ваш полный код (проект). может тогда я посмотрю, что не так. если хотите, чтобы я посмотрел - пришлите на [email protected] - person Tal Kanel; 03.08.2012
comment
Tal: Я отправил вам свой проект по электронной почте. Спасибо, что нашли время помочь мне. - person ChuongPham; 03.08.2012
comment
@Chuong: Я заметил, что ваша служба никогда не останавливалась. ты знаешь об этом? есть изменение, что экземпляр старой версии вашей службы все еще работает в фоновом режиме и никогда не останавливался / не изменялся) - person Tal Kanel; 03.08.2012
comment
добавьте этот код в свой activity.onDestroy - Intent intent = new Intent (this, BluetoothService.class); stopService (намерение); Я не вижу причин, по которым сервис продолжает работать после того, как действие было уничтожено. затем, если вы этого не делали раньше - полностью удалите (удалите) приложение с устройства / эмулятора, очистите + перестройте проект и попробуйте еще раз - person Tal Kanel; 03.08.2012
comment
Да моя плохая. Просто просмотрел мой файл журнала и увидел предупреждение от Android о том, что служба не закрывается. Спасибо, что указали мне на это. - person ChuongPham; 03.08.2012
comment
также странно, что служба вообще работает - потому что объявление в манифесте неверно - .BluetoothService он не должен работать, потому что ваш класс службы находится в другом пакете. измените пакет на правильный и перестройте, очистите, удалите .. - person Tal Kanel; 03.08.2012
comment
Я знаю, что это странно, но на самом деле я показываю эту службу Bluetooth :: onReceive () в файле журнала - и именно здесь я был озадачен. Во всяком случае, сейчас перестраиваем проект ... - person ChuongPham; 03.08.2012
comment
возможно, это сработало, потому что в какой-то момент служба была в другом пакете, и потому что вы не пересобирали проект - он все еще ссылается на старый .. - person Tal Kanel; 03.08.2012
comment
@Chuong: думаю, я знаю, в чем может быть проблема: измените строку serviceUpdateReceivedAction на com.onegoal.androidtest.serviceUpdateReceivedAction согласно документации - имя настраиваемого действия должно начинаться с пакета приложения - person Tal Kanel; 03.08.2012
comment
Ты сделал это, Таль. Наконец, получил службу для отображения сообщений от BroadcastReceiver - я изменил имя службы на полностью определенное эквивалентное имя - и все заработало. Я думаю, что вы точно знали о точке обслуживания для другого пакета - я пока не знаю почему, но я выясню. Отметьте свой ответ выше как правильный. Есть ли способ присудить вам больше баллов, поскольку вы очень помогли мне с этой проблемой - она ​​мучила меня последние несколько дней - наконец-то есть какое-то решение. - person ChuongPham; 03.08.2012