Android YouTubeSupportFragment播放器返回null

时间:2014-08-08 23:46:56

标签: java android-fragments this android-youtube-api youtube-data-api

我一直在开发基于演示的与YouTube相关的个人Android项目,但是我遇到了一个我似乎无法弄清楚(或理解)的问题。

原始代码使用基本PlayerView,而使用YouTubePlayerSupportFragment

只要player.cueVideo("VIDEOID")位于onInitializationSuccess内,该应用即可播放视频。但如果置于方法NullPointerException内,则会在播放器变量上使用playVideoAtSelection崩溃。

**原始代码在onInitializationSuccess中有以下行,但对我而言,它告诉我无法解析播放器。 **

我之前从未见过这样的this,所以它一直让我失望。

this.player = player; 

MainActivity.java代码:

public class MainActivity extends FragmentActivity implements
    AdapterView.OnItemClickListener,
    AdapterView.OnItemSelectedListener {

private final String LOG_TAG = MainActivity.class.getSimpleName();
AutoCompleteTextView atvSearch;
public String thumbnailURL;
public String mediaTitle;
public String videoID;
private TextView autoItem;
private ImageView autoImage;
private ArrayList<ArrayList<String>> resultList;

private static final String KEY_CURRENTLY_SELECTED_ID = "currentlySelectedId";

private YouTubePlayer mPlayer;
private YouTubePlayer player = null;

private ArrayAdapter<ListEntry> videoAdapter;
private Spinner videoChooser;

private MyPlayerStateChangeListener playerStateChangeListener;

private int currentlySelectedPosition;
private String currentlySelectedId;

private static final ListEntry[] ENTRIES = {
        new ListEntry("Androidify App", "irH3OSOskcE", false),
        new ListEntry("Chrome Speed Tests", "nCgQDjiotG0", false),
        new ListEntry("Playlist: Google I/O 2012", "PL56D792A831D0C362", true)};

@Override
protected void onCreate(Bundle savedInstanceState) {
    Log.v(LOG_TAG, "IN onCreate!");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.fragment_playlist, new PlaylistFragment())
                .commit();
    }

    //YouTubePlayerFragment playerFragment = YouTubePlayerFragment.newInstance("irH3OSOskcE");
    //getSupportFragmentManager().beginTransaction().replace(R.id.youtube_fragment, playerFragment).commit();

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

    YouTubePlayerSupportFragment youTubePlayerFragment = new YouTubePlayerSupportFragment();
    fragmentTransaction.add(R.id.youtube_fragment, youTubePlayerFragment);
    fragmentTransaction.commit();

    youTubePlayerFragment.initialize(DeveloperKey.DEVELOPER_KEY, new OnInitializedListener() {


        @Override
        public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player, boolean wasRestored) {
            mPlayer = player;
            mPlayer.setPlayerStateChangeListener(playerStateChangeListener);
            mPlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.MINIMAL);

            if (!wasRestored) {
                playVideoAtSelection();
            }
        }

        @Override
        public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
            //error
        }

    });

    AutoCompleteTextView autoCompView = (AutoCompleteTextView) findViewById(R.id.atv_search);
    autoCompView.setAdapter(new QueryAutoCompleteAdapter(this, R.layout.list_item));
    autoCompView.setOnItemClickListener(this);

    playerStateChangeListener = new MyPlayerStateChangeListener();

    videoChooser = (Spinner) findViewById(R.id.video_chooser);

    videoAdapter = new ArrayAdapter<ListEntry>(this, android.R.layout.simple_spinner_item, ENTRIES);
    videoAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    videoChooser.setOnItemSelectedListener(this);
    videoChooser.setAdapter(videoAdapter);

}

public void playVideoAtSelection() {
    if (mPlayer == null) {
        Log.v(LOG_TAG, "WE DUN GOOFD PLAYER IS NULL... ");
    }
    player.cueVideo("nCgQDjiotG0");
    Log.v(LOG_TAG, "WE HAVE ENTERED PLAYVIDEOATSELECTION... ");
    /*ListEntry selectedEntry = videoAdapter.getItem(currentlySelectedPosition);
    if (selectedEntry.id != currentlySelectedId && player != null) {
        currentlySelectedId = selectedEntry.id;
        if (selectedEntry.isPlaylist) {
            player.cuePlaylist(selectedEntry.id);
        } else {
            player.cueVideo(selectedEntry.id);
        }
    }*/
}

@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
    currentlySelectedPosition = pos;
    playVideoAtSelection();
}

@Override
public void onNothingSelected(AdapterView<?> parent) {
    // Do nothing.
}

@Override
protected void onSaveInstanceState(Bundle state) {
    super.onSaveInstanceState(state);
    state.putString(KEY_CURRENTLY_SELECTED_ID, currentlySelectedId);
}

@Override
protected void onRestoreInstanceState(Bundle state) {
    super.onRestoreInstanceState(state);
    currentlySelectedId = state.getString(KEY_CURRENTLY_SELECTED_ID);
}

private final class MyPlayerStateChangeListener implements YouTubePlayer.PlayerStateChangeListener {
    String playerState = "UNINITIALIZED";

    @Override
    public void onLoading() {
        playerState = "LOADING";
    }

    @Override
    public void onLoaded(String videoId) {
        playerState = String.format("LOADED %s", videoId);
    }

    @Override
    public void onAdStarted() {
        playerState = "AD_STARTED";
    }

    @Override
    public void onVideoStarted() {
        playerState = "VIDEO_STARTED";
    }

    @Override
    public void onVideoEnded() {
        playerState = "VIDEO_ENDED";
    }

    @Override
    public void onError(YouTubePlayer.ErrorReason reason) {
        playerState = "ERROR (" + reason + ")";
        if (reason == YouTubePlayer.ErrorReason.UNEXPECTED_SERVICE_DISCONNECTION) {
            // When this error occurs the player is released and can no longer be used.
            player = null;
            //setControlsEnabled(false);
        }
    }
}

private static final class ListEntry {

    public final String title;
    public final String id;
    public final boolean isPlaylist;

    public ListEntry(String title, String videoId, boolean isPlaylist) {
        this.title = title;
        this.id = videoId;
        this.isPlaylist = isPlaylist;
    }

    @Override
    public String toString() {
        return title;
    }
}

public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
    String str = (String) adapterView.getItemAtPosition(position);
    Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
}

public class QueryAutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {


    public QueryAutoCompleteAdapter(Context context, int textViewResourceId) {
        super(context, textViewResourceId);
    }

    @Override
    public int getCount() {
        return resultList.size();
    }

    @Override
    public String getItem(int index) {
        return resultList.get(index).toString();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        LayoutInflater inflater = LayoutInflater.from(getContext());
        if (row == null) {
            row = inflater.inflate(R.layout.list_item_query, parent, false);
        }
        ArrayList<String> text = resultList.get(position);
        String title = text.get(2);
        String url = text.get(1);
        videoID = text.get(0);
        Log.v(LOG_TAG, "YOOOOOO BAIIII: " + title + url);

        autoItem = (TextView) row.findViewById(R.id.list_item_title);
        autoImage = (ImageView) row.findViewById(R.id.list_item_thumbnail);

        autoItem.setText(title);

        Bitmap bm = null;
        try {
            InputStream in = new java.net.URL(url).openStream();
            bm = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            //Log.e("ERROR", e.getMessage());
            e.printStackTrace();
        }

        autoImage.setImageBitmap(bm);

        return row;
    }

    @Override
    public Filter getFilter() {
        Filter filter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                // Constraint is the input given by the user
                if (constraint != null) {
                    // Retrieve the autocomplete results.
                    resultList = autocomplete(constraint.toString());

                    int size = resultList.size();
                    for (int i=0; i<size; i++) {
                        //temp = resultList.get(i);
                        Log.v(LOG_TAG, "YOOOOOO: " + resultList.get(i));
                        thumbnailURL = resultList.get(i).get(1);
                        mediaTitle = resultList.get(i).get(2);
                    }

                    Log.v(LOG_TAG, "YOOOOOO: " + thumbnailURL + " " + mediaTitle);
                    // Assign the data to the FilterResults
                    filterResults.values = resultList;
                    filterResults.count = resultList.size();
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                if (results != null && results.count > 0) {
                    notifyDataSetChanged();
                }
                else {
                    notifyDataSetInvalidated();
                }
            }};
        return filter;
    }
}

private ArrayList<ArrayList<String>> autocomplete(String input) {
    ArrayList<ArrayList<String>> queries = null;

    // If there's no query, there is nothing to look up
    if (input.length() == 0) {
        return null;
    }

    String songQuery = input;

    // These two need to be declared outside the try/catch
    // so that they can be closed in the finally block.
    HttpURLConnection urlConnection = null;
    BufferedReader reader = null;

    // Will contain the raw JSON response as a string.
    String queryJsonStr = null;

    String part = "id,snippet";
    String order = "relevance";
    String q = songQuery;
    String type = "video";
    String categoryID = "kind";
    String key = DeveloperKey.DEVELOPER_KEY;

    try {
        // Construct the URL for the query
        final String BASE_URL = "https://www.googleapis.com/youtube/v3/search?";
        final String PART_PARAM = "part";
        final String ORDER_PARAM = "order";
        final String QUERY_PARAM = "q";
        final String TYPE_PARAM = "type";
        final String CATEGORYID_PARAM = "videoCategoryId";
        final String KEY_PARAM = "key";

        Uri builtUri = Uri.parse(BASE_URL).buildUpon()
                .appendQueryParameter(PART_PARAM, part)
                .appendQueryParameter(ORDER_PARAM, order)
                .appendQueryParameter(QUERY_PARAM, q)
                .appendQueryParameter(TYPE_PARAM, type)
                .appendQueryParameter(CATEGORYID_PARAM, categoryID)
                .appendQueryParameter(KEY_PARAM, key)
                .build();

        URL url = new URL(builtUri.toString());
        Log.v(LOG_TAG, "BUILT URI: " + builtUri.toString());
        // Create the request to YouTube, and open the connection
        urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("GET");
        urlConnection.connect();

        // Read the input stream into a String
        InputStream inputStream = urlConnection.getInputStream();
        StringBuffer buffer = new StringBuffer();
        if (inputStream == null) {
            // Nothing to do.
            return null;
        }
        reader = new BufferedReader(new InputStreamReader(inputStream));

        String line;
        while ((line = reader.readLine()) != null) {
            // Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
            // But it does make debugging a *lot* easier if you print out the completed
            // buffer for debugging.
            buffer.append(line + "\n");
        }

        if (buffer.length() == 0) {
            // Stream was empty.  No point in parsing.
            return null;
        }

        queryJsonStr = buffer.toString();

        Log.v(LOG_TAG, "Query JSON String: " + queryJsonStr);

    } catch (IOException e) {
        Log.e(LOG_TAG, "ERROR ", e);
        // If the code didn't successfully get the weather data, there's no point in attempting
        // to parse it.
        return null;

    } finally {
        if (urlConnection != null) {
            urlConnection.disconnect();
        }
        if (reader != null) {
            try {
                reader.close();
            } catch (final IOException e) {
                Log.e("PlaceholderFragment", "Error closing stream", e);
            }
        }
    }

    try {

        JSONObject jsonObject = new JSONObject(queryJsonStr);
        QueryJSONParser queryJSONParser = new QueryJSONParser();

        // Getting the parsed data as a list construct
        queries = queryJSONParser.parse(jsonObject);

    } catch (Exception e) {
        Log.d("Exception", e.toString());
    }

    return queries;
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

}

相关XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<fragment
    android:name="com.google.android.youtube.player.YouTubePlayerSupportFragment"
    android:id="@+id/youtube_fragment"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="8dp"
    android:orientation="horizontal"
    android:gravity="top">

    <include
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        layout="@layout/player_controls_container" />
</LinearLayout>

非常感谢任何帮助!

LOGCAT:

08-08 19:52:23.404    6040-6040/com.android.youtube V/MainActivity﹕ WE DUN GOOFD PLAYER IS NULL...
08-08 19:52:23.404    6040-6040/com.android.youtube D/AndroidRuntime﹕ Shutting down VM
08-08 19:52:23.404    6040-6040/com.android.youtube W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x41894da0) 
08-08 19:52:23.414    6040-6040/com.android.youtube E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.android.youtube, PID: 6040
java.lang.NullPointerException
        at com.android.youtube.MainActivity.playVideoAtSelection(MainActivity.java:132)
        at com.android.youtube.MainActivity.onItemSelected(MainActivity.java:148)

1 个答案:

答案 0 :(得分:0)

您收到 NullPointerException ,因为您的播放器变量未初始化。您已对此内容进行了评论:

this.player = player;

问题是什么 this.player = player

指的是当前对象

例如:

public class myClass{
   int x;
   public myClass(int x){
   this.x = x;
  }
}

在上面的示例中,您使用了 this ,因为您要将x的值赋给x(myClass的属性)。

PS:如果您对感到困惑,可以轻松执行以下操作:

将变量名称更改为其他名称,可能是 mPlayer 并改变 this.player = playermPlayer = player;

<强>编辑: 您已在课堂外宣布YouTubePlayer。 将其移入,即在覆盖onCreate(..)方法之前。

<强>更新 由于玩家不是班级的属性,因此不会知道它是什么。这类似于不声明任何变量。