Почему намерение, отправленное LocalBroadCastManager из IntentService, не получено BroadCastReceiver в классе Activity?

ChooseLanguageFragment.java

Intent explicitGetNumberServiceIntentUSA = new Intent(getActivity(), GetNumberService.class);
explicitGetNumberServiceIntentUSA.putExtra("country", "USA");
getActivity().startService(explicitGetNumberServiceIntentUSA);

Вот как вызывается GetNumberService.

Вот как массив передается из GetNumberService.java

Intent mobileNumbersIntent = new Intent();
mobileNumbersIntent.putStringArrayListExtra("mobileNumbers", mobileNumberList);
mobileNumbersIntent.setAction(ChooseNumber1.MobileNumberBroadcastReceiver.MOBILE_NO_RECEIVER);
mobileNumbersIntent.addCategory(Intent.CATEGORY_DEFAULT);
mobileNumbersIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //this is needed when callling startActivity() outisde an Activity            
sendBroadcast(mobileNumbersIntent);

в методе onHandleIntent().

GetNumberService отлично справляется со своей задачей.

ChooseNumber1.java

public class ChooseNumber1 extends AppCompatActivity {
    private MobileNumberBroadcastReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        IntentFilter intentFilter = new IntentFilter(MobileNumberBroadcastReceiver.MOBILE_NO_RECEIVER);
        intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
        receiver = new MobileNumberBroadcastReceiver();
        registerReceiver(receiver, intentFilter);
        setContentView(R.layout.activity_choose_number1);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    @Override
    protected void onDestroy(){
        unregisterReceiver(receiver);
        super.onDestroy();
    }

    public class MobileNumberBroadcastReceiver extends BroadcastReceiver {

        public static final String MOBILE_NO_RECEIVER = "abcd";
        ArrayList<String> mobileNumbersList = new ArrayList<>();
        ListView mobileNumberListView;
        ArrayAdapter<String> mobileNumberAdapter;

        @Override
        public void onReceive(Context context, Intent intent) {
          //  if(intent.getAction().equals(GetNumberService.MOBILE_NUMBER_LIST_PASS_ACTION)){
                mobileNumbersList = intent.getStringArrayListExtra("mobileNumberList");
         //   }
            mobileNumberAdapter = new ArrayAdapter<String>(new ChooseNumbers(),
                    R.layout.list_item_numbers, R.id.list_item_number_textview, mobileNumbersList);

            mobileNumberListView = (ListView) findViewById(R.id.listViewNumberList);
            mobileNumberListView.setAdapter(mobileNumberAdapter);
        }
    }

}

activity_choose_number1.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.a2ndnumber.a2ndnumber.ChooseNumbers">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_choose_number1" />

</android.support.design.widget.CoordinatorLayout>

content_choose_number1.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.a2ndnumber.a2ndnumber.ChooseNumber1"
    tools:showIn="@layout/activity_choose_number1">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/listViewNumberList"/>

</RelativeLayout>

PS 2:

Проблема в том, что я не могу получить mobileNumbersIntent в ChooseNumber1.java или ChooseNumbersFragment.java. Я думаю, что проблема в BroadcastManager.java. Если я отлаживаю, он переходит к Handler.java и нескольким другим классам и, наконец, mId=-1 и без ошибок в трассировке стека. я поражен

PS: AndroidManifest.xml

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

    <!-- TODO : Add permissions -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- Contacts -->
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".ChooseLanguage"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
        </activity>
        <activity
            android:name=".Choose_Country"
            android:label="@string/app_name"
            android:parentActivityName=".ChooseLanguage"
            android:theme="@style/AppTheme.NoActionBar">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.a2ndnumber.a2ndnumber.ChooseLanguage" />
        </activity>
        <activity
            android:name=".MainActivity"
            android:noHistory="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <service android:name=".service.GetNumberService" />

        <activity
            android:name=".ChooseNumber1"
            android:label="@string/title_activity_choose_number1"
            android:parentActivityName=".Choose_Country"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.a2ndnumber.a2ndnumber.Choose_Country" />
        </activity>
    </application>

</manifest>

PS: я сильно изменил свой код после просмотра множества примеров и ответов в Stackoverflow. Это мой последний код. Похоже, проблема связана с фильтром намерений и/или получением намерения с помощью действия. Пожалуйста помогите. Спасибо.


person sofs1    schedule 06.09.2016    source источник
comment
используйте getView().findViewById();   -  person Vishal Patoliya ツ    schedule 06.09.2016
comment
Опубликуйте также полную трассировку стека. Переместите эту строку ArrayAdapter<String> mobileNumberAdapter ниже ListView mobileNumberListView, а затем setAdapter.   -  person Jay Rathod RJ    schedule 06.09.2016
comment
Возможный дубликат Что такое исключение NullPointerException и как его исправить?   -  person joc    schedule 06.09.2016
comment
Я предполагаю, что это не NPE из-за findViewById() и ListView, а NPE, потому что вы передали нулевой массив в ArrayAdapter. Опубликуйте трассировку стека для вашего NPE.   -  person laalto    schedule 06.09.2016
comment
inflater = (LayoutInflater) context.getSystemService (Context.LAYOUT_INFLATER_SERVICE);   -  person gaurang    schedule 07.09.2016
comment
@gaurang Зачем мне добавлять этот код? И добавление его в ChooseNumbersFragment onCreateView() не имело никакого значения.   -  person sofs1    schedule 07.09.2016
comment
Во-первых, Intent, которое вы транслируете, не имеет действия, которое вы фильтруете в Activity - GetNumberService.MOBILE_NUMBER_LIST_PASS_ACTION. Вам нужно создать экземпляр Intent с помощью этого действия или установить его на Intent с помощью setAction(). Кроме того, флаг не нужен. Если действие не помогло, опубликуйте свой манифест и объясните, где и когда вы запускаете свой IntentService.   -  person Mike M.    schedule 11.09.2016
comment
@МайкМ. Извините, что оставил здесь старый код. Да, я это понял и обновил в своей IDE. Я поставил последний код здесь сейчас. Ждем вашей помощи. Спасибо. Я запускаю IntentService в другом классе, который правильно запускает IntentService, и я вижу, как метод onHandlerIntent() выполняет свою работу.   -  person sofs1    schedule 11.09.2016
comment
@МайкМ. Похоже, проблема с фильтром намерений   -  person sofs1    schedule 11.09.2016
comment
Ключи для ArrayList не совпадают. У вас "mobileNumbers" в эфире, но "mobileNumberList" в приемнике. Ваш ресивер вообще работает? Кроме того, ваш текущий код больше не использует LocalBroadcastManager. И вам по-прежнему не нужен флаг — или категория, если уж на то пошло — в трансляции Intent.   -  person Mike M.    schedule 11.09.2016
comment
мой Бог. Я больше не использую LocalBroadcastmanager   -  person sofs1    schedule 11.09.2016
comment
Я исправил дополнительную проблему намерения mobileNumbers в ChooseNumber1.java. Но все же я не вижу arrayList, заполненный в пользовательском интерфейсе ChooseNumber1. Еще одна проблема, с которой я сталкиваюсь, заключается в том, что после нажатия return в onHandlerIntent() из GetNumberService() я вообще не могу достичь каких-либо точек останова ChooseNumber1.java   -  person sofs1    schedule 11.09.2016
comment
@МайкМ. Верен ли мой AndroidManifest.xml?   -  person sofs1    schedule 11.09.2016
comment
Манифест в порядке. Вы уверены, что ChooseNumber1 работает во время трансляции? Я имею в виду, как вы начинаете это Activity? Если вы все делаете правильно, когда запускаете Service, почему бы просто не начать Service с ChooseNumber1? Кроме того, если у вас возникли проблемы с точками останова, вы можете попробовать использовать печать журнала.   -  person Mike M.    schedule 11.09.2016
comment
Нет. ChooseNumber1 должен запускаться, когда GetNumberService завершает получение информации из удаленной базы данных. @МайкМ. OK. Мое требование. В ChooseCountryFragment.java (в пользовательском интерфейсе), когда пользователь выбирает страну, --> я запускаю GetNumberService.java, который извлекает мобильные номера из центральной базы данных с использованием JSON ---> после получения данных они должны быть отправлены в ChooseNumber1, а ChooseNumber1 должен быть начатым.   -  person sofs1    schedule 11.09.2016
comment
Отправка широковещательной рассылки не запускает Activity. Вот для чего нужен метод startActivity().   -  person Mike M.    schedule 11.09.2016
comment
Но если я добавлю startActivity(new Intent(getActivity(), ChooseNumber1.class)); в GetNumberService после sendBroadcast(), я получаю ошибки из-за раздувания макетов без данных в массиве arrayAdapter. Как лучше всего запустить ChooseNumber1 в моем случае.   -  person sofs1    schedule 11.09.2016
comment
Вам вообще не нужна трансляция/приемник. Присоедините свой ArrayList к Intent, используемому для запуска ChooseNumber1.   -  person Mike M.    schedule 11.09.2016
comment
Как? Вы имеете в виду Intent mobileNumbersIntent = new Intent(); mobileNumbersIntent.putStringArrayListExtra("mobileNumbers", mobileNumberList); mobileNumbersIntent.setAction(ChooseNumber1.MobileNumberBroadcastReceiver.MOBILE_NO_RECEIVER); startActivity(mobileNumbersIntent); в GetNumberservice.java? Не могли бы вы предоставить мне код.   -  person sofs1    schedule 11.09.2016
comment
Вам не нужно действие. Используйте явный Intent, который указывает класс Activity, как показано здесь. В onCreate() ChooseNumber1 getIntent() вернет Intent с доп.   -  person Mike M.    schedule 11.09.2016
comment
Вы хотите, чтобы я сделал явное намерение в GetNumberService.java или в ChooseLanguageFragment.java   -  person sofs1    schedule 11.09.2016
comment
хорошо-хорошо. Понятно. Я уже делаю это в GetNumberService.java. Но как раздуть намерение или поиграть с getIntent() в ChooseNumber1.java, чтобы отобразить его в пользовательском интерфейсе?   -  person sofs1    schedule 11.09.2016
comment
@МайкМ. Думаю, мы близки к исправлению. Пожалуйста, помогите мне, сэр. Пожалуйста.   -  person sofs1    schedule 11.09.2016
comment
getIntent() вернет Intent, использованный для запуска Activity. Извлеките из него дополнительные ArrayList и сделайте то же самое, что вы пытались сделать в приемнике.   -  person Mike M.    schedule 11.09.2016
comment
@МайкМ. Огромное спасибо силе тонны. Я новичок в программировании под андроид. Я только что закончил смотреть уроки, и это моя первая программа. Большое спасибо за терпение и терпение со мной. Я чувствовал, что доставал тебя слишком многими вопросами. Большое спасибо.   -  person sofs1    schedule 11.09.2016
comment
@МайкМ. Могу ли я узнать, в каких ситуациях следует использовать BroadcastManager? Я знаю, что мы должны использовать его в разных приложениях, но можно ли использовать его внутри приложения?   -  person sofs1    schedule 11.09.2016
comment
LocalBroadcastManager работает только в одном приложении. Вы не можете использовать его для связи между приложениями.   -  person Mike M.    schedule 11.09.2016
comment
@MikeM.Привет, Майк, если ты сделаешь это ответом, я бы хотел выбрать твое в качестве рабочего решения.   -  person sofs1    schedule 12.09.2016


Ответы (5)


Желаемый поток не требует настройки вещания и приемника. Поскольку ChooseNumber1 Activity должен запускаться после того, как Service завершит свою работу, вам просто нужно присоединить ArrayList к Intent, используемому для запуска ChooseNumber1. Затем список может быть получен в onCreate(), и ваш ListView и его Adapter могут быть немедленно инициализированы, вместо того, чтобы пытаться ждать широковещательной рассылки.

Например, в вашем Service после составления списка:

Intent mobileNumbersIntent = new Intent(this, ChooseNumber1.class);
mobileNumbersIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mobileNumbersIntent.putStringArrayListExtra("mobileNumbers", mobileNumberList);
startActivity(mobileNumbersIntent);

Затем в Activity:

public class ChooseNumber1 extends AppCompatActivity {

    private ArrayAdapter<String> mobileNumberAdapter;
    private ArrayList<String> mobileNumbersList = new ArrayList<>();
    private ListView mobileNumberListView;

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

        ...

        mobileNumberListView = (ListView) findViewById(R.id.listViewNumberList);

        mobileNumbersList = getIntent().getStringArrayListExtra("mobileNumbers");
        if(mobileNumbersList != null) {
            mobileNumberAdapter = new ArrayAdapter<String>(this,
                                                           R.layout.list_item_numbers,
                                                           R.id.list_item_number_textview,
                                                           mobileNumbersList);
            mobileNumberListView.setAdapter(mobileNumberAdapter);
        }
    }
}
person Mike M.    schedule 13.09.2016

Ваш findViewById() в порядке и возвращает ненулевое значение.

Проблема связана с адаптером, как показано в трассировке стека: список mobileNumbersList, который вы ему передаете, является нулевым в то время, когда адаптер назначается. ArrayAdapter нужен ненулевой массив.

(Есть ряд других проблем с кодом — это как раз NPE.)

person laalto    schedule 06.09.2016
comment
Поскольку я объявил mobileNumberList статическим в ChooseNumbers.java, а mobileNumberList заполняется в BroadCastReceiver, не должен ли mobileNumberList в ChooseNumbersFragment.java иметь значения, которые были заполнены в ChooseNumbers.java? - person sofs1; 06.09.2016
comment
Широковещательный приемник не обязательно срабатывает до создания экземпляра вашего фрагмента. - person laalto; 06.09.2016
comment
1) Разве ChooseNumbers.java не выполняется первым перед CHooseNumbersFragment.java? - person sofs1; 06.09.2016
comment
2) Могу ли я переместить IntentFilter filter = new IntentFilter(); filter.addAction(GetNumberService.MOBILE_NUMBER_LIST_PASS_ACTION); LocalBroadcastManager bm = LocalBroadcastManager.getInstance(this); bm.registerReceiver(mBroadcastReceiver, filter); в ChooseNumberFragments.java? это решение сначала заполнить mobileNumberList? - person sofs1; 06.09.2016
comment
Широковещательный приемник не обязательно срабатывает до создания экземпляра вашего фрагмента. Как сделать, чтобы BroadcastReceiver выполнялся, а mobileNumberList заполнялся первым, прежде чем создавать экземпляр фрагмента? - person sofs1; 06.09.2016
comment
Код не выполняется для каждого файла. Широковещательные приемники являются асинхронными и срабатывают после того, как была проведена трансляция. Попытка заставить его выполняться первым - неправильная проблема для решения. Вместо этого сначала сделайте адаптер пустым и добавляйте в него новый контент при его получении. Не забудьте уведомить адаптер при изменении списка. - person laalto; 06.09.2016
comment
добавить новый контент к нему, когда вы его получите. - Как это сделать, сэр? Я совершенно поражен. - person sofs1; 06.09.2016
comment
Например, developer.android.com/reference/android/ виджет/ - person laalto; 06.09.2016
comment
Я понимаю, что могу использовать метод add для добавления arrayList в адаптер, но как мне кодировать, добавлять только при получении контента. Также проблема заключается в том, что фрагмент создается до заполнения массиваList. И без элементов в Arraylist это был бы пустой список. - person sofs1; 07.09.2016
comment
Вы упомянули в ответе, что в коде есть другие проблемы. - person sofs1; 07.09.2016
comment
Ok. Я понял, что база данных потеряла соединение, и добавил autoReconnect=true в JNDI, и теперь arrayList заполняется значением. Но теперь еще ChooseNumber или ChooseNumberFragment не создаются. Не могли бы вы мне помочь? Поразил этим за ›48 часов. - person sofs1; 07.09.2016
comment
Поля для комментариев на самом деле предназначены не для расширенных обсуждений или вопросов/ответов, а только для комментариев и пояснений по обсуждаемой теме. Не стесняйтесь задавать дополнительные вопросы, если у вас возникли проблемы. - person laalto; 07.09.2016
comment
Давайте продолжим обсуждение в чате. - person sofs1; 07.09.2016

Я бы предложил проверить, работает ли этот простой код:

внутри деятельности:

@Override
      protected void onResume() {
        super.onResume();
        IntentFilter intFilt = new IntentFilter(MYBROADCASTINGSTRING);
        registerReceiver(updbr,intFilt);
      }
    @Override
      protected void onPause() {
        super.onPause();
        unregisterReceiver(updbr);
      }


        private BroadcastReceiver updbr = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent2) {
                    try {
Log.d("MYLOG", "gotcha!");
                    } catch (Exception e) {

                    }
                }
            };

Трансляция в сервисе при ловле:

Intent intentBR = new Intent(MYBROADCASTINGSTRING);
        intentBR.putExtra(somestring, "teststring");
        sendBroadcast(intentBR);

Где MYBROADCASTINGSTRING - некоторая константа. Например. public final static String MYBROADCASTINGSTRING = "MYBROADCASTINGSTRING"; Не нужно улучшать AndroidManifest.xml. Это работает?

person Vyacheslav    schedule 11.09.2016

Когда вы отправляете трансляцию, вы передаете добавку, подобную этой

mobileNumbersIntent.putStringArrayListExtra("mobileNumbers", mobileNumberList);

И когда вы читаете это дополнение в BroadcastReceiver, вы делаете это.

mobileNumbersList = intent.getStringArrayListExtra("mobileNumberList");

Вы должны использовать тот же ключ для дополнительных функций. Я бы рекомендовал использовать константу в IntentService для этой цели.

public static final string EXTRA_MOBILE_NUMBERS = "mobile_numbers";

Затем вы можете делать такие вещи, как:

mobileNumbersIntent.putStringArrayListExtra(MyIntentService.EXTRA_MOBILE_NUMBERS, mobileNumberList);

а также

mobileNumbersList = intent.getStringArrayListExtra(MyIntentService.EXTRA_MOBILE_NUMBERS);
person Binoy Babu    schedule 11.09.2016

Для обработки результата от IntentService используйте ResultReciver вместо широковещательного приемника.

Так,

Шаг 1. Создайте обработчик результатов, используя ResultReceiver внутри действия.

public ResultReceiver downloadReceiver = new ResultReceiver(new Handler()) {
    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {
        super.onReceiveResult(resultCode, resultData);
        //Broadcast /send the result code in intent service based on your logic(success/error) handle with switch
        switch (resultCode) {
            case 1: {
                //Get the resultData and do your logic here
                //Update your list view item here
                break;
            }
            case 2: {
                //Get the resultData and do your logic here
                //Update your list view item here
                break;
            }
        }
    }
}; 

Шаг 2. Поместите обработчик результатов в намерение и запустите службу намерения

Intent intent = new Intent(getContext(), DownloadService.class);
intent.putExtra("receiver",downloadReceiver);

Шаг 3. Обработайте намерение в классе обслуживания (получите значение обработчика результата)

final ResultReceiver receiver;

@Override
protected void onHandleIntent(Intent intent) {
    receiver = intent.getParcelableExtra("receiver");
}

Шаг 4. Отправка/передача данных обработчику результатов

//based on your logic, change the result code and data

//Add your result data (success scenario)
Bundle bundle = new Bundle();
bundle.putString("result","Some text");
receiver.send(1,bundle);

//Add your result data (failure scenario)
receiver.send(0,bundle);
person Pandiarajan    schedule 12.09.2016