2016-10-21 3 views
2

비교적 간단한 작업을 수행하려고합니다. 원격 서버에서 JSON을 가져 오는 서비스를 시작하는 프래그먼트가 있습니다. 그런 다음 JSON을 브로드 캐스트를 사용하여 원래의 호출 단편으로 다시 전달하려는 경우 BroadcastReceiver가 단편의 익명 클래스로 정의됩니다. 그러나Android - 동적으로 등록 된 브로드 캐스트 수신기에서 브로드 캐스트를 전달할 수 없음 오류가 발생했습니다.

, 나는이 작업을 수행하려고 할 때마다, 나는 다음과 같은 오류가 계속 : 여기

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

}

그리고 다음은

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) 
이 조각 내 코드입니다 서비스 코드 :

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

}

나는 의도를 통해 원시 JSON 문자열을 보내고, 브로드 캐스트 리시버를 별도의 클래스로 정의하고, JSON을 직렬화 된 ArrayList로 변환하고, 의도를 통해 보내고, 마지막으로 시도하고있다. 그것을 묶음으로 모두 포함시키고 보내는 것.

기괴한 것은 내 급우에게 아주 비슷한 코드가 잘 작동하는 것 같습니다. 문제를 일으킬 수있는 코드와 내 코드 사이에 차이점을 볼 수 없습니다. 또한, 의도를 통해 다른 String을 보내려고하면 잘 작동하는 것처럼 보입니다. 방송 수신자가 수신하고 onReceive를 호출해야합니다. '브로드 캐스트를 전달할 수 없습니다.'라는 오류는이 특정 데이터 집합을 전달하려고 할 때 발생하는 것으로 보입니다.

+0

은'PostCodesResult.Result'가 직렬화 가능합니까? – nandsito

+0

예, 내부 클래스와 외부 클래스 모두 직렬화 가능합니다. –

+0

나는 그것이 문제의 원인인지는 모르겠지만 귀하의 단편에 몇 가지 이슈가 있습니다. 수신자를 이중 등록하고 (Frag가 다시 시작될 때까지) 등록이 취소되지는 않습니다. 그리고 수신기는 활동에 등록됩니다. 현재 Frag 나 그 액티비티가 화면을 벗어나면 수신자는 어떻게됩니까? – nandsito

답변

0

이 문제도 발생했습니다. 나는 내가 바이트 배열의 크기를 줄임으로써 그것을 해결했다는 것을 알아 냈다. 확인 해봐!

0

원래 질문이 얼마 전 게시되었지만 최근에이 문제가 발생했으며 누군가 다른 사람들을 돕기 위해 내가 수정 한 내용을 게시하고 싶었습니다.

다음 두 가지 사항을 변경하여 문제를 해결할 수있었습니다. 확실하게 문제의 정확한 원인을 확인할 수 없으므로 두 가지 변경 사항이 모두 필요한지 확실하지 않습니다. 그러나 앱이 무엇을하고 있는지에 따라, 이것은 이전 코드보다 개선 된 것이므로 둘 다 유지했습니다. 의도 행동의

정의

이 앱은 백그라운드 작업을 수행하기위한 IntentService를 확장하는 클래스를 사용하는 상수. 이 클래스는 서비스가 작업을 완료 할 때 브로드 캐스팅되는 인 텐트에 대한 "작업"값으로 사용되는 정적 최종 String 값을 정의합니다.

이러한 문자열은 작업의 의미 (예 : 'SAVE_COMMENT')와 일치하는 값으로 정의되었지만 앱의 패키지 이름을 포함하지 않은 것으로 나타났습니다.

Android 인 텐트 및 IntentFilter 설명서에서 ...

https://developer.android.com/guide/components/intents-filters.html

If you define your own actions, be sure to include your app's package name as a prefix.

나는 패키지 이름을 포함하는 이러한 문자열의 값을 변경했습니다.

나는 이것을 증명할 수 없었지만 액션 이름 중 하나가 해당 장치의 다른 앱에 정의 된 동작과 충돌 할 수 있는지 궁금합니다. LocalBroadcastManager

응용에

스위치 컨텍스트를 사용했다 :: sendBroadcast()를이 작업을 완료 할 때마다 텐트를 방송 할 수 있습니다. 앱의 서비스에 의해 수행되는 모든 로직은 해당 앱을위한 것이므로 대신 LocalBroadcastManager :: sendBroadcast()를 사용하도록 전환했습니다. 이렇게하면 앱 내에 브로드 캐스트가 유지되어 다른 앱과의 충돌 가능성을 방지 할 수 있습니다.

관련 문제