Не може да се извика метод на 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());
                }               
            }
        }
    };  
}

И в моя клас по активност имам това:

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 преди всичко в дейност, тогава работи - но не и в [отделна] услуга. Смаян съм.

Моят 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
трябва ли да регистрирате Receiver в Manifest и както каза @Lucifer взехте ли разрешение?? Дори аз не мисля, че можете да направите TextView tvStatus = (TextView) mActivity.findViewById(R.id.tvtatus); в твоя приемник..?   -  person AAnkit    schedule 03.08.2012


Отговори (1)


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

BroadcastReceiver никога не трябва да бъде статичен. може да причини много проблеми.

друг наистина лош проблем с дизайна на вашия код - поддържането на препратка към дейността в услугата и използването й за модифициране на изгледи е наистина грешно нещо. това може да доведе до лесно запаметяване на праз. правилното защо да комуникирате между Service и Activity е чрез внедряване на Messanger на android или изпращане на излъчвания между тях чрез 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
Тал: Пробвах вашите кодове, но нито методът bluetoothReceiver в класа на услугата, нито методът mServiceUpdatesReceiver в класа активност не се задействаха. Сложих някои кодове за отстраняване на грешки, включително команда 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 - тогава, когато дейността не е forground (или екран на устройството е близо) предаването няма да бъде получено - 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
Тал: Изпратих ви моя проект по имейл. Благодаря, че отделихте време да ми помогнете. - person ChuongPham; 03.08.2012
comment
@Chuong: Забелязах, че услугата ви никога не е спирана. наясно ли си с това има промяна, че екземплярът от старата версия на вашата услуга все още работи във фонов режим и никога не е бил спрян/променен) - person Tal Kanel; 03.08.2012
comment
добавете този код към вашата дейност.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