Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
527 views
in Technique[技术] by (71.8m points)

broadcastreceiver - Android - getting "can't deliver broadcast" error on dynamically registered broadcast receiver

I'm trying to perform a relatively simple task: I have a fragment that starts a service to pull some JSON from a remote server. I then want to pass that JSON back to the original calling fragment using a broadcast, with the BroadcastReceiver defined as an anonymous class in the fragment.

However, whenever I try to do this, I keep getting the following error:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.roundarch.codetest, PID: 21974
    android.app.RemoteServiceException: can't deliver broadcast
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1631)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

code:

public class Part3Fragment extends Fragment {

    PostCodeAdapter postCodeAdapter;
    ListView listView;
    BroadcastReceiver receiver;
    IntentFilter intentFilter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_part3, null);

        initialiseReceiver();

        View emptyView = (View) view.findViewById(R.id.empty_textview);
        ListView listView = (ListView) view.findViewById(R.id.part3_listview);
        listView.setEmptyView(emptyView);

        // TODO - the listview will need to be provided with a source for data

        // TODO - (optional) you can set up handling to list item selection if you wish

        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        initialiseReceiver();
        getActivity().startService(new Intent(getActivity(), Part3Service.class));
    }

    public void initialiseReceiver(){
        receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Bundle bundle = intent.getBundleExtra("bundle");
                ArrayList<PostCodesResult.Result> postcodes = (ArrayList<PostCodesResult.Result>) bundle.getSerializable("postcodeArray");
                updatePostcodes(postcodes);
            }
        };
        intentFilter = new IntentFilter("JSON_RECEIVED");

        getActivity().registerReceiver(receiver, intentFilter);
    }

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


    }

    private void updatePostcodes(ArrayList<PostCodesResult.Result> postcodes) {
        if (postcodes.size() > 0){
            postCodeAdapter = new PostCodeAdapter(getActivity(), R.layout.part3_listview_item, postcodes);
            listView.setAdapter(postCodeAdapter);
            postCodeAdapter.notifyDataSetChanged();
        }
    }
}

And here is the code for the service:

public class Part3Service extends Service {

    private final String TAG = this.getClass().getSimpleName();

    // TODO - we can use this as the broadcast intent to filter for in our Part3Fragment
    public static final String ACTION_SERVICE_DATA_UPDATED = "com.roundarch.codetest.ACTION_SERVICE_DATA_UPDATED";

    private List<Map<String, String>> data = null;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.i(TAG, "Service has started");
        new PostCodeRetriever().execute("http://gomashup.com/json.php?fds=geo/usa/zipcode/state/IL");


        return START_STICKY;
    }

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

    private void updateData() {
        // TODO - start the update process for our data
    }

    private void broadcastDataUpdated(String jsonString) {
        Intent intent = new Intent();
        intent.setAction("JSON_RECEIVED");
        ArrayList<PostCodesResult.Result> postcodes = new ArrayList<>();
        if (jsonString != null) {
            Gson gson = new Gson();
            PostCodesResult result = gson.fromJson(jsonString, PostCodesResult.class);
            postcodes.addAll(result.getResult());
        }
        Bundle bundle = new Bundle();
        bundle.putSerializable("postcodeArray", postcodes);
        intent.putExtra("bundle", bundle);
        sendBroadcast(intent);
        stopSelf();
    }

    class PostCodeRetriever extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... params) {

            Uri uri = Uri.parse(params[0]);

            String jsonString = "";

            try {
                URL postcodesUrl = new URL(uri.toString());
                InputStream inputStream = null;

                HttpURLConnection connection = (HttpURLConnection) postcodesUrl.openConnection();
                connection.connect();

                inputStream = connection.getInputStream();
                InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                StringBuilder stringBuilder = new StringBuilder();

                String line = "";
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line);
                }

                stringBuilder.deleteCharAt(0);
                stringBuilder.deleteCharAt(stringBuilder.length() -1);

                jsonString = stringBuilder.toString();

                bufferedReader.close();
                inputStreamReader.close();
                inputStream.close();
                connection.disconnect();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }


            return jsonString;

        }

        @Override
        protected void onPostExecute(String jsonString) {

            broadcastDataUpdated(jsonString);
            super.onPostExecute(jsonString);
        }
    }
}

I've tried so many different things: sending only the raw JSON string via the intent, defining the broadcast receiver as a separate class, converting the JSON to a serialized ArrayList and sending that through the intent, and finally trying to include it all in a bundle and sending that.

The bizarre thing is that very similar code seems to work fine for my classmates - I can't see any differences between their code and my code that might be causing the problem (and neither can they). Additionally, if I try to just send a different String through the intent then that seems to work fine - the broadcast receiver picks it up and onReceive is called as it should be. The "Cannot deliver broadcast" error only seems to occur when attempting to deliver this specific dataset, and only for me!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I had this issue too. I found out the I broadcast on the intent huge amount of data (which was a big byte array..) So I solved it by decreasing the size of the byte array. Check it out!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.8k users

...