-1

我查看了其他线程,但没有找到解决方案,除了最初检测到API 21即棒棒糖。虽然,我在棒棒糖以及后棒棒糖版本面临这个问题。YouTube Player API抛出异常

我正在使用YouTube数据API,在我的应用程序中显示特定频道的内容。我很成功地从API获取响应并在RecyclerView中显示内容。

但是,当我尝试加载视频YouTubeSupportFragment时,该应用程序崩溃,同时调用cueVideo()YouTubeSupportFragment,但有以下例外。

注:我正在使用YouTube API的最新版本(1.2.2)。

这里是由YouTube Player抛出的异常:

E/AndroidRuntime: FATAL EXCEPTION: main 
    Process: com.acme.youtubeplayer, PID: 16757 
    java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.google.android.youtube.api.service.START } 
     at android.app.ContextImpl.validateServiceIntent(ContextImpl.java:2101) 
     at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:2225) 
     at android.app.ContextImpl.bindService(ContextImpl.java:2203) 
     at android.content.ContextWrapper.bindService(ContextWrapper.java:560) 
     at com.google.android.youtube.player.internal.r.e(Unknown Source) 
     at com.google.android.youtube.player.YouTubePlayerView.a(Unknown Source) 
     at com.google.android.youtube.player.YouTubePlayerSupportFragment.a(Unknown Source) 
     at com.google.android.youtube.player.YouTubePlayerSupportFragment.onCreateView(Unknown Source) 
     at android.support.v4.app.Fragment.performCreateView(Fragment.java:2192) 
     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1299) 
     at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528) 
     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595) 
     at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:758) 
     at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2363) 
     at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2149) 
     at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2103) 
     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2013) 
     at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:710) 
     at android.os.Handler.handleCallback(Handler.java:739) 
     at android.os.Handler.dispatchMessage(Handler.java:95) 
     at android.os.Looper.loop(Looper.java:145) 
     at android.app.ActivityThread.main(ActivityThread.java:7007) 
     at java.lang.reflect.Method.invoke(Native Method) 
     at java.lang.reflect.Method.invoke(Method.java:372) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199) 

这里是我的ListFragment.java,其中应用程序崩溃:

public class ListFragment extends android.support.v4.app.Fragment { 
    // TODO: Rename parameter arguments, choose names that match 
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER 
    private static final String ARG_PARAM1 = "param1"; 
    private static final String ARG_PARAM2 = "param2"; 

    // TODO: Rename and change types of parameters 
    private String mParam1; 
    private String mParam2; 

    private static final String KEY_TRANSITION_EFFECT = "transition_effect"; 
    private static final int RECOVERY_REQUEST = 1; 

    private int mCurrentTransitionEffect = JazzyHelper.HELIX; 
    private JazzyRecyclerViewScrollListener jazzyScrollListener; 
    YouTubePlayerView youtube_player; 
    MyPlayerStateChangeListener playerStateChangeListener; 
    MyPlaybackEventListener playbackEventListener; 
    YouTubePlayer playerFragment; 

    JSONObject jObjectAPI; 
    JSONArray jArrayResponse; 
    int listSize; 
    JSONObject jObjectResponse, jObject; 

    public static final String YOUTUBE_API = "https://www.googleapis.com/youtube/v3/search?key=" + Config.YOUTUBE_API_KEY + "&channelId=" + Config.YOUTUBE_CHANNEL_ID + "&part=snippet,id&order=date&maxResults=20"; 

    //Local Variables 
    RecyclerView recyclerView; 
    Button seekToButton; 

    YouTubePlayerSupportFragment youTubePlayerFragment; 
    String[] thumbnailVideo; 
    String[] titleVideo; 
    String[] descriptionVideo; 
    String[] idVideo; 
    int itemLayoutRes = R.layout.item; 
    boolean isStaggered = false; 

    private OnFragmentInteractionListener mListener; 

    private ProgressDialog pDialog; 

    public ListFragment() { 
     // Required empty public constructor 
    } 

    /** 
    * Use this factory method to create a new instance of 
    * this fragment using the provided parameters. 
    * 
    * @param param1 Parameter 1. 
    * @param param2 Parameter 2. 
    * @return A new instance of fragment ListFragment. 
    */ 
    // TODO: Rename and change types and number of parameters 
    public static ListFragment newInstance(String param1, String param2) { 
     ListFragment fragment = new ListFragment(); 
     Bundle args = new Bundle(); 
     args.putString(ARG_PARAM1, param1); 
     args.putString(ARG_PARAM2, param2); 
     fragment.setArguments(args); 
     return fragment; 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     if (getArguments() != null) { 
      mParam1 = getArguments().getString(ARG_PARAM1); 
      mParam2 = getArguments().getString(ARG_PARAM2); 
     } 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     View view = inflater.inflate(R.layout.fragment_list, container, false); 
     // Inflate the layout for this fragment 

     recyclerView = (RecyclerView) view.findViewById(R.id.rv_video_list); 

     recyclerView.setLayoutManager(createLayoutManager(itemLayoutRes, isStaggered)); 
     recyclerView.setHasFixedSize(false); 
     new GetList().execute(); 

     return view; 
    } 

    // TODO: Rename method, update argument and hook method into UI event 
    public void onButtonPressed(Uri uri) { 
     if (mListener != null) { 
      mListener.onFragmentInteraction(uri); 
     } 
    } 

    @Override 
    public void onAttach(Context context) { 
     super.onAttach(context); 
     if (context instanceof OnFragmentInteractionListener) { 
      mListener = (OnFragmentInteractionListener) context; 
     } 
    } 

    @Override 
    public void onDetach() { 
     super.onDetach(); 
     mListener = null; 
    } 

    /** 
    * This interface must be implemented by activities that contain this 
    * fragment to allow an interaction in this fragment to be communicated 
    * to the activity and potentially other fragments contained in that 
    * activity. 
    * <p> 
    * See the Android Training lesson <a href= 
    * "http://developer.android.com/training/basics/fragments/communicating.html" 
    * >Communicating with Other Fragments</a> for more information. 
    */ 
    public interface OnFragmentInteractionListener { 
     // TODO: Update argument type and name 
     void onFragmentInteraction(Uri uri); 
    } 

    private RecyclerView.LayoutManager createLayoutManager(int itemLayoutRes, boolean isStaggered) { 
     if (itemLayoutRes == R.layout.item) { 
      return new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false); 
     } else { 
      if (isStaggered) { 
       return new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL); 
      } else { 
       return new GridLayoutManager(getActivity(), 1); 
      } 
     } 
    } 

    private void setupJazziness(int effect) { 
     mCurrentTransitionEffect = effect; 
     jazzyScrollListener.setTransitionEffect(mCurrentTransitionEffect); 
    } 

    private void showMessage(String message) { 
     Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show(); 
    } 

    public final class MyPlaybackEventListener implements YouTubePlayer.PlaybackEventListener { 

     @Override 
     public void onPlaying() { 
      // Called when playback starts, either due to user action or call to play(). 
      showMessage("Playing"); 
     } 

     @Override 
     public void onPaused() { 
      // Called when playback is paused, either due to user action or call to pause(). 
      showMessage("Paused"); 
     } 

     @Override 
     public void onStopped() { 
      // Called when playback stops for a reason other than being paused. 
      showMessage("Stopped"); 
     } 

     @Override 
     public void onBuffering(boolean b) { 
      // Called when buffering starts or ends. 
     } 

     @Override 
     public void onSeekTo(int i) { 
      // Called when a jump in playback position occurs, either 
      // due to user scrubbing or call to seekRelativeMillis() or seekToMillis() 
     } 
    } 

    public final class MyPlayerStateChangeListener implements YouTubePlayer.PlayerStateChangeListener { 

     @Override 
     public void onLoading() { 
      // Called when the youtube_player is loading a video 
      // At this point, it's not ready to accept commands affecting playback such as play() or pause() 
      playerFragment.loadVideo(idVideo.toString()); 
     } 

     @Override 
     public void onLoaded(String s) { 
      // Called when a video is done loading. 
      // Playback methods such as play(), pause() or seekToMillis(int) may be called after this callback. 
      playerFragment.play(); 
     } 

     @Override 
     public void onAdStarted() { 
      // Called when playback of an advertisement starts. 
      playerFragment.pause(); 
     } 

     @Override 
     public void onVideoStarted() { 
      // Called when playback of the video starts. 
     } 

     @Override 
     public void onVideoEnded() { 
      // Called when the video reaches its end. 
      if (playerFragment.hasNext()) { 
       playerFragment.next(); 
      } 
     } 

     @Override 
     public void onError(YouTubePlayer.ErrorReason errorReason) { 
      // Called when an error occurs. 
      Toast.makeText(getActivity(), "Please check your Internet Connection", Toast.LENGTH_LONG).show(); 
     } 
    } 

    public static JSONObject getJSONObjectFromURL(String urlString) throws IOException, JSONException { 

     HttpURLConnection urlConnection = null; 

     URL url = new URL(urlString); 

     urlConnection = (HttpURLConnection) url.openConnection(); 

     urlConnection.setRequestMethod("GET"); 
     urlConnection.setReadTimeout(10000 /* milliseconds */); 
     urlConnection.setConnectTimeout(15000 /* milliseconds */); 

     urlConnection.setDoOutput(true); 

     urlConnection.connect(); 

     BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream())); 

     char[] buffer = new char[1024]; 

     String jsonString; 

     StringBuilder sb = new StringBuilder(); 
     String line; 
     while ((line = br.readLine()) != null) { 
      sb.append(line + "\n"); 
     } 
     br.close(); 

     jsonString = sb.toString(); 

     System.out.println("JSON: " + jsonString); 

     return new JSONObject(jsonString); 
    } 

    private class GetList extends AsyncTask<Void, Void, Void> { 

     @Override 
     protected void onPreExecute() { 
      super.onPreExecute(); 
      // Showing progress dialog 
      pDialog = new ProgressDialog(getActivity()); 
      pDialog.setMessage("Please wait..."); 
      pDialog.setCancelable(false); 
      pDialog.show(); 

     } 

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

      try { 
       jObjectAPI = getJSONObjectFromURL(YOUTUBE_API); 
       Log.e("response", String.valueOf(jObjectAPI)); 
       jArrayResponse = jObjectAPI.getJSONArray("items"); 
       Log.e("array", String.valueOf(jArrayResponse)); 

       listSize = jArrayResponse.length(); 

       thumbnailVideo = new String[listSize]; 
       titleVideo = new String[listSize]; 
       descriptionVideo = new String[listSize]; 
       idVideo = new String[listSize]; 

       for (int i = 0; i < listSize; i++) { 
        jObjectResponse = jArrayResponse.getJSONObject(i); 
        thumbnailVideo[i] = jObjectResponse.getJSONObject("snippet").getJSONObject("thumbnails") 
          .getJSONObject("default") 
          .optString("url"); 
        titleVideo[i] = jObjectResponse.getJSONObject("snippet").optString("title"); 

        if (!(jObjectResponse.getJSONObject("snippet").optString("description").equals("")) 
          && !(jObjectResponse.getJSONObject("snippet").optString("description").equals(null)) 
          && (jObjectResponse.getJSONObject("snippet").optString("description").length() > 0)) { 
         descriptionVideo[i] = jObjectResponse.getJSONObject("snippet").optString("description"); 
        } else { 
         descriptionVideo[i] = "No Description Found"; 
        } 

        idVideo[i] = jObjectResponse.getJSONObject("id").optString("videoId"); 
       } 
      } catch (JSONException e) { 
       e.printStackTrace(); 
       Log.e("JSON Exception", e.toString()); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

      return null; 
     } 

     @Override 
     protected void onPostExecute(Void result) { 
      super.onPostExecute(result); 
      // Dismiss the progress dialog 
      if (pDialog.isShowing()) 
       pDialog.dismiss(); 
      /** 
      * Updating parsed JSON data into ListView 
      **/ 

      recyclerView.setAdapter(new VideoListAdapter(thumbnailVideo, titleVideo, descriptionVideo, idVideo, itemLayoutRes, getActivity())); 
      jazzyScrollListener = new JazzyRecyclerViewScrollListener(); 
      recyclerView.setOnScrollListener(jazzyScrollListener); 

      setupJazziness(R.anim.slide_left_in); 
      playerStateChangeListener = new MyPlayerStateChangeListener(); 
      playbackEventListener = new MyPlaybackEventListener(); 

      youTubePlayerFragment = new YouTubePlayerSupportFragment(); 
      youTubePlayerFragment.initialize(Config.YOUTUBE_API_KEY, new YouTubePlayer.OnInitializedListener() { 

       @Override 
       public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player, boolean wasRestored) { 
        playerFragment = player; 

        player.setPlayerStateChangeListener(playerStateChangeListener); 
        player.setPlaybackEventListener(playbackEventListener); 

        if (!wasRestored) { 
         player.cueVideos(Arrays.asList(idVideo)); 
        } 
       } 

       @Override 
       public void onInitializationFailure(YouTubePlayer.Provider arg0, YouTubeInitializationResult errorReason) { 
        // TODO Auto-generated method stub 
        if (errorReason.isUserRecoverableError()) { 
         errorReason.getErrorDialog(getActivity(), RECOVERY_REQUEST).show(); 
        } else { 
         String error = String.format(getString(R.string.player_error), errorReason.toString()); 
         Toast.makeText(getActivity(), error, Toast.LENGTH_LONG).show(); 
        } 
       } 
      }); 

      android.support.v4.app.FragmentManager fmPlayer = getFragmentManager(); 
      FragmentTransaction transaction = fmPlayer.beginTransaction(); 
      transaction.replace(R.id.youtube_player_view, youTubePlayerFragment); 
      transaction.commit(); 
     } 
    } 
} 

这里是我的适配器类

public class VideoListAdapter extends Adapter<VideoListAdapter.VideoListViewHolder> { 

    private List<String> thumbnail; 
    private List<String> title; 
    private List<String> desc; 
    private List<String> id; 
    private int itemLayoutRes; 
    private static Activity mContext; 

    public VideoListAdapter(String[] videoThumbnail, String[] videoTitle, String[] videoDesc, String[] videoId, int itemLayoutRes, Activity context) { 
     this.thumbnail = Arrays.asList(videoThumbnail); 
     this.title = Arrays.asList(videoTitle); 
     this.desc = Arrays.asList(videoDesc); 
     this.id = Arrays.asList(videoId); 
     this.itemLayoutRes = itemLayoutRes; 
     this.mContext = context; 
    } 

    @Override 
    public VideoListAdapter.VideoListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 
     View view; 
     view = inflater.inflate(itemLayoutRes, parent, false); 
     return new VideoListViewHolder(view); 
    } 

    @Override 
    public void onBindViewHolder(final VideoListViewHolder holder, final int position) { 

     Picasso.with(mContext).load(thumbnail.get(position)).into(new Target() { 
      @Override 
      public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { 
       // loaded bitmap is here (bitmap) 
       holder.thumbnailVideo.setImageBitmap(bitmap); 
      } 

      @Override 
      public void onBitmapFailed(Drawable errorDrawable) { 
       Toast.makeText(mContext, "Image load failed", Toast.LENGTH_LONG).show(); 
      } 

      @Override 
      public void onPrepareLoad(Drawable placeHolderDrawable) { 

      } 
     }); 

     Log.e("thumbnail Adapter", String.valueOf(thumbnail.get(position))); 
     holder.titleVideo.setText(title.get(position)); 
     holder.descVideo.setText(desc.get(position)); 

     holder.idVideo = id.get(position); 
    } 

    @Override 
    public int getItemCount() { 
     return title.size(); 
    } 

    @Override 
    public int getItemViewType(int position) { 
     // return isStaggered ? position % 2 : 0; 
     return position; 
    } 

    public static class VideoListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 
     final TextView titleVideo, descVideo; 
     final YouTubeThumbnailView thumbnailVideo; 

     String idVideo; 

     public VideoListViewHolder(View view) { 
      super(view); 
      thumbnailVideo = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail_video); 
      titleVideo = (TextView) view.findViewById(R.id.title_video); 
      descVideo = (TextView) view.findViewById(R.id.desc_video); 
     } 

     @Override 
     public void onClick(View v) { 
      Intent intent = new Intent(mContext, YouTubeBaseActivity.class); 
      //Intent intent = YouTubeStandalonePlayer.createVideoIntent((Activity) v.getContext(), Config.YOUTUBE_API_KEY, idVideo); 
      v.getContext().startActivity(intent); 
     } 
    } 
} 

回答

0

最后我摆脱了这个问题。我将YouTubeSupportFragment替换为YouTubeBaseActivity,并使用YouTubePlayerView播放视频。

换句话说,我用Activity延伸YouTubeBaseActivity播放视频,而不是Fragment

希望它能帮助某人解决问题。