我一直在开发基于演示的与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)
答案 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 = player
至mPlayer = player;
<强>编辑:强> 您已在课堂外宣布YouTubePlayer。 将其移入,即在覆盖onCreate(..)方法之前。
<强>更新强> 由于玩家不是班级的属性,因此不会知道它是什么。这类似于不声明任何变量。