2

ChooseLanguageFragment.java

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

This is how the GetNumberService is called.

This is how the arraylist is passed from 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);

in onHandleIntent() method.

GetNumberService does its job perfectly.

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:

Problem is, I am not able to receive the mobileNumbersIntent in ChooseNumber1.java or ChooseNumbersFragment.java. I think the issue is with BroadcastManager.java. If I debug, it goes to Handler.java and few other classes and finally mId=-1 and no error in stack trace. I am struck

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: I have modified my code a lot after going through tons of examples and answers in Stackoverflow. This is my latest code. Look like the issue is with intent-filter and/or getting intent using action. Please help me. Thanks.

K Neeraj Lal
  • 6,768
  • 3
  • 24
  • 33
sofs1
  • 3,834
  • 11
  • 51
  • 89
  • use getView().findViewById(); – Vishal Patoliya ツ Sep 06 '16 at 07:34
  • Post your full *stack trace* also. Move this line `ArrayAdapter mobileNumberAdapter` below `ListView mobileNumberListView` and then `setAdapter`. – Jay Rathod Sep 06 '16 at 07:34
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – joc Sep 06 '16 at 07:40
  • I guess this is not a NPE because of the `findViewById()` and `ListView` but a NPE because you passed a null array to `ArrayAdapter`. Post the stacktrace for your NPE. – laalto Sep 06 '16 at 07:43
  • inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); – gaurang Sep 07 '16 at 10:53
  • @gaurang Why should I add this code? And adding it in ChooseNumbersFragment onCreateView() didn't do any difference. – sofs1 Sep 07 '16 at 11:00
  • For one thing, the `Intent` you're broadcasting doesn't have the action you're filtering for in the `Activity` - `GetNumberService.MOBILE_NUMBER_LIST_PASS_ACTION`. You need to instantiate the `Intent` with that action, or set it on the `Intent` with `setAction()`. Also, the flag is unnecessary. If the action doesn't fix it, please post your manifest, and explain where and when you're starting your `IntentService`. – Mike M. Sep 10 '16 at 22:58
  • @MikeM. Sorry for leaving the old code here. Yeah I realized that and updated it in my IDE. I have put the latest code here now. Looking forward for your help. Thanks. I am starting the IntentService in another class which properly triggers IntentService and I am able to see onHandlerIntent() method doing its job. – sofs1 Sep 10 '16 at 23:27
  • @MikeM. Look like the issue is with intent-filter – sofs1 Sep 10 '16 at 23:33
  • The keys for the `ArrayList` extra don't match. You have `"mobileNumbers"` at the broadcast, but `"mobileNumberList"` in the Receiver. Is your Receiver running at all? Also, your current code is no longer using `LocalBroadcastManager`. And, you still don't need the flag - or the category, for that matter - on the broadcast `Intent`. – Mike M. Sep 10 '16 at 23:39
  • omg. I no longer use LocalBroadcastmanager – sofs1 Sep 10 '16 at 23:42
  • I fixed the "mobileNumbers" issue of intent extra in ChooseNumber1.java. But still I don't see arrayList populated in UI by ChooseNumber1. The another issue I face is, after hitting `return` in `onHandlerIntent()` of `GetNumberService()` I am not at all able to reach any breakpoints of ChooseNumber1.java – sofs1 Sep 10 '16 at 23:48
  • @MikeM. Is my AndroidManifest.xml is correct? – sofs1 Sep 10 '16 at 23:51
  • The manifest is fine. Are you certain `ChooseNumber1` is running when the broadcast occurs? I mean, how are you starting that `Activity`? If you're doing it right when you're starting the `Service`, why not just start the `Service` from `ChooseNumber1`? Also, if you're having trouble with breakpoints, you might try using log prints. – Mike M. Sep 11 '16 at 00:03
  • No. ChooseNumber1 should be made to run when GetNumberService completes getting information from remote database. @MikeM. OK. My Requirement. In ChooseCountryFragment.java (in UI) when user selects a country, --> I start GetNumberService.java which fetches mobile Numbers from central database using JSON ---> after the fetching the data, it should be sent to ChooseNumber1 and ChooseNumber1 should be started. – sofs1 Sep 11 '16 at 00:18
  • Sending a broadcast does not start an `Activity`. That's what the `startActivity()` method is for. – Mike M. Sep 11 '16 at 00:21
  • But if I add `startActivity(new Intent(getActivity(), ChooseNumber1.class));` in GetNumberService after sendBroadcast() I get errors because of inflating layouts without data in arraylist of arrayAdapter. What is the best way to start ChooseNumber1 in my case. – sofs1 Sep 11 '16 at 00:24
  • You don't need a broadcast/Receiver at all. Attach your `ArrayList` to the `Intent` used to start `ChooseNumber1`. – Mike M. Sep 11 '16 at 00:29
  • How? You mean like this `Intent mobileNumbersIntent = new Intent(); mobileNumbersIntent.putStringArrayListExtra("mobileNumbers", mobileNumberList); mobileNumbersIntent.setAction(ChooseNumber1.MobileNumberBroadcastReceiver.MOBILE_NO_RECEIVER); startActivity(mobileNumbersIntent);` in GetNumberservice.java?Could you provide me the code. – sofs1 Sep 11 '16 at 00:35
  • You don't need the action. Use an explicit `Intent`, which specifies the `Activity` class, like is shown [here](http://stackoverflow.com/a/16529854). In `ChooseNumber1`'s `onCreate()`, `getIntent()` will return the `Intent` with the extra. – Mike M. Sep 11 '16 at 00:40
  • You want me to do the explicit Intent in `GetNumberService.java` or in `ChooseLanguageFragment.java` – sofs1 Sep 11 '16 at 00:46
  • ok ok. Got it. I already do that in `GetNumberService.java`. But how to inflate the intent or play with `getIntent()` in `ChooseNumber1.java` to show it in UI? – sofs1 Sep 11 '16 at 00:48
  • @MikeM. I think we are close to the fix. Please help me sir. Please. – sofs1 Sep 11 '16 at 01:07
  • `getIntent()` will return the `Intent` used to start the `Activity`. Retrieve the `ArrayList` extra from it, and do the same thing you were trying to do in the Receiver. – Mike M. Sep 11 '16 at 01:09
  • @MikeM. Thanks a ton to the power of ton. I am a newbie to android programming. I just finished watching tutorials and this is my first program. Thank you very much for being patience and bearing with me. I felt like I pestered you with too many questions. Thanks a lot. – sofs1 Sep 11 '16 at 01:21
  • @MikeM. May I know under what situations one should use BroadcastManager? I know we should use it across applications, but is it fine to use within an app? – sofs1 Sep 11 '16 at 01:23
  • `LocalBroadcastManager` only works within a single app. You can't use it to communicate between apps. – Mike M. Sep 11 '16 at 01:30
  • 1
    @MikeM.Hi Mike, If you make it as answer, I would like to choose yours as working solution. – sofs1 Sep 12 '16 at 20:25

5 Answers5

1

The desired flow doesn't require a broadcast and Receiver setup. Since the ChooseNumber1 Activity is to be started after the Service has completed its work, you simply need to attach the ArrayList to the Intent used to start ChooseNumber1. The list can then be retrieved in onCreate(), and your ListView and its Adapter can be immediately initialized, rather than trying to wait for a broadcast.

For example, in your Service, after the list has been assembled:

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

Then, in the 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);
        }
    }
}
Mike M.
  • 38,532
  • 8
  • 99
  • 95
0

Your findViewById() is just fine and returns a non-null.

The problem is with the adapter as seen in the stacktrace: The mobileNumbersList list you're passing to it is null at the time when the adapter is assigned. ArrayAdapter needs a non-null array.

(There are a number of other problems with the code - this is just the NPE.)

laalto
  • 150,114
  • 66
  • 286
  • 303
  • Since I have declared mobileNumberList as static in ChooseNumbers.java, and mobileNumberList being populated in BroadCastReceiver, shouldn't mobileNumberList in ChooseNumbersFragment.java have values that was populated in ChooseNumbers.java? – sofs1 Sep 06 '16 at 07:55
  • The broadcast receiver does not necessarily fire before your fragment is instantiated. – laalto Sep 06 '16 at 07:55
  • 1) Doesn't ChooseNumbers.java get executed first before CHooseNumbersFragment.java? – sofs1 Sep 06 '16 at 07:56
  • 2) Can I move `IntentFilter filter = new IntentFilter(); filter.addAction(GetNumberService.MOBILE_NUMBER_LIST_PASS_ACTION); LocalBroadcastManager bm = LocalBroadcastManager.getInstance(this); bm.registerReceiver(mBroadcastReceiver, filter); ` to ChooseNumberFragments.java? is that the solution to have mobileNumberList populated first? – sofs1 Sep 06 '16 at 07:58
  • "The broadcast receiver does not necessarily fire before your fragment is instantiated." How do I make the BroadcastReceiver is executed and mobileNumberList is populated first, before instantiating the fragment? – sofs1 Sep 06 '16 at 08:00
  • Code does not execute per file basis. Broadcast receivers are asynchronous and fire after there's been a broadcast. Trying to force it to execute first is the wrong problem to solve. Instead, make the adapter empty at first and add new content to it when you receive it. Remember to notify the adapter when changing the list. – laalto Sep 06 '16 at 08:01
  • "add new content to it when you receive it." - How to do that sir? I am totally struck. – sofs1 Sep 06 '16 at 08:33
  • For example, https://developer.android.com/reference/android/widget/ArrayAdapter.html#add(T) – laalto Sep 06 '16 at 09:07
  • I get that I can use add method to add arrayList to adapter, but how do I code, "add only when content is received". Also the issue here is the fragment get constructed before populating arrayList. And without items in Arraylist it would be an empty list view. – sofs1 Sep 06 '16 at 22:07
  • You mentioned in the answer that there are other problems in the code – sofs1 Sep 07 '16 at 08:23
  • Ok. I figured out that database lost connection and added autoReconnect=true in JNDI and now the arrayList is populated with value. But now still the ChooseNumber or ChooseNumberFragment is not built up. Could you please help me? Struck with this for >48 hours. – sofs1 Sep 07 '16 at 10:49
  • Comment fields are really not for extended discussions or questions/answers, just for comments and clarifications on the topic at hand. Feel free to post additional questions if you're experiencing problems. – laalto Sep 07 '16 at 10:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/122818/discussion-between-user3705478-and-laalto). – sofs1 Sep 07 '16 at 10:54
0

I would suggest to inspect whether works this simple code:

inside Activity:

@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) {

                    }
                }
            };

Cast broadbast in the service while catching:

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

Where the MYBROADCASTINGSTRING is some constant. E.g. public final static String MYBROADCASTINGSTRING = "MYBROADCASTINGSTRING"; It doesn't not need to improve AndroidManifest.xml. Does it work?

Vyacheslav
  • 26,359
  • 19
  • 112
  • 194
0

When you are sending the broadcast you are passing an extra like this

mobileNumbersIntent.putStringArrayListExtra("mobileNumbers", mobileNumberList);

And when you are reading that extra in the BroadcastReceiver, you're doing this.

mobileNumbersList = intent.getStringArrayListExtra("mobileNumberList");

You should be using the same key for extras. I would recommend using a constant in IntentService for this purpose.

public static final string EXTRA_MOBILE_NUMBERS = "mobile_numbers";

Then you could do stuff like:

mobileNumbersIntent.putStringArrayListExtra(MyIntentService.EXTRA_MOBILE_NUMBERS, mobileNumberList);

and

mobileNumbersList = intent.getStringArrayListExtra(MyIntentService.EXTRA_MOBILE_NUMBERS);
Binoy Babu
  • 16,699
  • 17
  • 91
  • 134
0

For handling result from IntentService, Use ResultReciver instead of the broadcast receiver.

Like this,

Step 1: Create the result handler using ResultReceiver inside activity

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;
            }
        }
    }
}; 

Step 2: Put the result handler inside the intent and start the intent service

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

Step 3: Handle the intent in service class(get the value of result handler)

final ResultReceiver receiver;

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

Step 4: Send/Broadcast the data to the result handler

//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);
Pandiarajan
  • 322
  • 2
  • 9