- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
从https://github.com/youtube/yt-android-player得到代码
修改了 VideoListDemoActivity.java 以在 AsyncTask 中使用 JSON 动态加载视频列表:
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.examples.youtubeapidemo;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayer.OnFullscreenListener;
import com.google.android.youtube.player.YouTubePlayer.OnInitializedListener;
import com.google.android.youtube.player.YouTubePlayer.Provider;
import com.google.android.youtube.player.YouTubePlayerFragment;
import com.google.android.youtube.player.YouTubeThumbnailLoader;
import com.google.android.youtube.player.YouTubeThumbnailLoader.ErrorReason;
import com.google.android.youtube.player.YouTubeThumbnailView;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ListFragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.res.Configuration;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.TextView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* A sample Activity showing how to manage multiple YouTubeThumbnailViews in an adapter for display
* in a List. When the list items are clicked, the video is played by using a YouTubePlayerFragment.
* <p>
* The demo supports custom fullscreen and transitioning between portrait and landscape without
* rebuffering.
*/
@TargetApi(13)
public final class VideoListDemoActivity extends Activity implements OnFullscreenListener {
/** The duration of the animation sliding up the video in portrait. */
private static final int ANIMATION_DURATION_MILLIS = 300;
/** The padding between the video list and the video in landscape orientation. */
private static final int LANDSCAPE_VIDEO_PADDING_DP = 5;
private VideoListFragment listFragment;
private VideoFragment videoFragment;
private View videoBox;
private View closeButton;
private boolean isFullscreen;
/*
*
* new code
*
*/
private static String url = "http://gdata.youtube.com/feeds/api/users/DayAndNightNewsChd/uploads?v=2&alt=jsonc";
public static List<VideoEntry> VIDEO_LIST;
public static List<VideoEntry> list = new ArrayList<VideoEntry>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
*
* execute asynctask to get the video list
*
*/
new JSONParse().execute();
}
/*
*
* AsyncTask
*
*/
private class JSONParse extends AsyncTask<Void, Void, Void>
{
private ProgressDialog pDialog;
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(VideoListDemoActivity.this);
pDialog.setMessage("Getting Data ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
@Override
protected Void doInBackground(Void... arg0) {
/*
*
*
* get the data from server and load it into the array
*
*
*/
try {
HttpClient client = new DefaultHttpClient();
HttpUriRequest request = new HttpGet(url);
HttpResponse response = client.execute(request);
String jsonString = StreamUtils.convertToString(response.getEntity().getContent());
JSONObject json = new JSONObject(jsonString);
JSONArray jsonArray = json.getJSONObject("data").getJSONArray("items");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String title = jsonObject.getString("title");
String video = jsonObject.getString("id");
Log.d("YOUTUBE", title);
list.add(new VideoEntry(title, video));
}
} catch (ClientProtocolException e) {
//Log.e("Feck", e);
} catch (IOException e) {
//Log.e("Feck", e);
} catch (JSONException e) {
//Log.e("Feck", e);
}
VIDEO_LIST = Collections.unmodifiableList(list);
return null;
}
@Override
protected void onPostExecute(Void result) {
/*
*
*
* this should be done in the oncreate() but causes app to crash
*
*
*/
setContentView(R.layout.video_list_demo);
listFragment = (VideoListFragment) getFragmentManager().findFragmentById(R.id.list_fragment);
videoFragment =
(VideoFragment) getFragmentManager().findFragmentById(R.id.video_fragment_container);
closeButton = findViewById(R.id.close_button);
videoBox = findViewById(R.id.video_box);
videoBox.setVisibility(View.INVISIBLE);
layout();
pDialog.dismiss();
}
}//end async
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
layout();
}
@Override
public void onFullscreen(boolean isFullscreen) {
this.isFullscreen = isFullscreen;
layout();
}
/**
* Sets up the layout programatically for the three different states. Portrait, landscape or
* fullscreen+landscape. This has to be done programmatically because we handle the orientation
* changes ourselves in order to get fluent fullscreen transitions, so the xml layout resources
* do not get reloaded.
*/
private void layout() {
boolean isPortrait =
getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
listFragment.getView().setVisibility(isFullscreen ? View.GONE : View.VISIBLE);
listFragment.setLabelVisibility(isPortrait);
closeButton.setVisibility(isPortrait ? View.VISIBLE : View.GONE);
if (isFullscreen) {
videoBox.setTranslationY(0); // Reset any translation that was applied in portrait.
setLayoutSize(videoFragment.getView(), MATCH_PARENT, MATCH_PARENT);
setLayoutSizeAndGravity(videoBox, MATCH_PARENT, MATCH_PARENT, Gravity.TOP | Gravity.LEFT);
} else if (isPortrait) {
setLayoutSize(listFragment.getView(), MATCH_PARENT, MATCH_PARENT);
setLayoutSize(videoFragment.getView(), MATCH_PARENT, WRAP_CONTENT);
setLayoutSizeAndGravity(videoBox, MATCH_PARENT, WRAP_CONTENT, Gravity.BOTTOM);
} else {
videoBox.setTranslationY(0); // Reset any translation that was applied in portrait.
int screenWidth = dpToPx(getResources().getConfiguration().screenWidthDp);
setLayoutSize(listFragment.getView(), screenWidth / 4, MATCH_PARENT);
int videoWidth = screenWidth - screenWidth / 4 - dpToPx(LANDSCAPE_VIDEO_PADDING_DP);
setLayoutSize(videoFragment.getView(), videoWidth, WRAP_CONTENT);
setLayoutSizeAndGravity(videoBox, videoWidth, WRAP_CONTENT,
Gravity.RIGHT | Gravity.CENTER_VERTICAL);
}
}
@SuppressLint("NewApi")
public void onClickClose(@SuppressWarnings("unused") View view) {
listFragment.getListView().clearChoices();
listFragment.getListView().requestLayout();
videoFragment.pause();
videoBox.animate()
.translationYBy(videoBox.getHeight())
.setDuration(ANIMATION_DURATION_MILLIS)
.withEndAction(new Runnable() {
@Override
public void run() {
videoBox.setVisibility(View.INVISIBLE);
}
});
}
/**
* A fragment that shows a static list of videos.
*/
public static final class VideoListFragment extends ListFragment {
/*
private static final List<VideoEntry> VIDEO_LIST;
static {
List<VideoEntry> list = new ArrayList<VideoEntry>();
list.add(new VideoEntry("YouTube Collection", "Y_UmWdcTrrc"));
list.add(new VideoEntry("GMail Tap", "1KhZKNZO8mQ"));
list.add(new VideoEntry("Chrome Multitask", "UiLSiqyDf4Y"));
list.add(new VideoEntry("Google Fiber", "re0VRK6ouwI"));
list.add(new VideoEntry("Autocompleter", "blB_X38YSxQ"));
list.add(new VideoEntry("GMail Motion", "Bu927_ul_X0"));
list.add(new VideoEntry("Translate for Animals", "3I24bSteJpw"));
VIDEO_LIST = Collections.unmodifiableList(list);
}
*/
private PageAdapter adapter;
private View videoBox;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//new JSONParse().execute();
adapter = new PageAdapter(getActivity(), VIDEO_LIST);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
videoBox = getActivity().findViewById(R.id.video_box);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
setListAdapter(adapter);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
String videoId = VIDEO_LIST.get(position).videoId;
VideoFragment videoFragment =
(VideoFragment) getFragmentManager().findFragmentById(R.id.video_fragment_container);
videoFragment.setVideoId(videoId);
// The videoBox is INVISIBLE if no video was previously selected, so we need to show it now.
if (videoBox.getVisibility() != View.VISIBLE) {
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// Initially translate off the screen so that it can be animated in from below.
videoBox.setTranslationY(videoBox.getHeight());
}
videoBox.setVisibility(View.VISIBLE);
}
// If the fragment is off the screen, we animate it in.
if (videoBox.getTranslationY() > 0) {
videoBox.animate().translationY(0).setDuration(ANIMATION_DURATION_MILLIS);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
adapter.releaseLoaders();
}
public void setLabelVisibility(boolean visible) {
adapter.setLabelVisibility(visible);
}
}
/**
* Adapter for the video list. Manages a set of YouTubeThumbnailViews, including initializing each
* of them only once and keeping track of the loader of each one. When the ListFragment gets
* destroyed it releases all the loaders.
*/
private static final class PageAdapter extends BaseAdapter {
private final List<VideoEntry> entries;
private final List<View> entryViews;
private final Map<YouTubeThumbnailView, YouTubeThumbnailLoader> thumbnailViewToLoaderMap;
private final LayoutInflater inflater;
private final ThumbnailListener thumbnailListener;
private boolean labelsVisible;
public PageAdapter(Context context, List<VideoEntry> entries) {
this.entries = entries;
entryViews = new ArrayList<View>();
thumbnailViewToLoaderMap = new HashMap<YouTubeThumbnailView, YouTubeThumbnailLoader>();
inflater = LayoutInflater.from(context);
thumbnailListener = new ThumbnailListener();
labelsVisible = true;
}
public void releaseLoaders() {
for (YouTubeThumbnailLoader loader : thumbnailViewToLoaderMap.values()) {
loader.release();
}
}
public void setLabelVisibility(boolean visible) {
labelsVisible = visible;
for (View view : entryViews) {
view.findViewById(R.id.text).setVisibility(visible ? View.VISIBLE : View.GONE);
}
}
@Override
public int getCount() {
return entries.size();
}
@Override
public VideoEntry getItem(int position) {
return entries.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
VideoEntry entry = entries.get(position);
// There are three cases here
if (view == null) {
// 1) The view has not yet been created - we need to initialize the YouTubeThumbnailView.
view = inflater.inflate(R.layout.video_list_item, parent, false);
YouTubeThumbnailView thumbnail = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail);
thumbnail.setTag(entry.videoId);
thumbnail.initialize(DeveloperKey.DEVELOPER_KEY, thumbnailListener);
} else {
YouTubeThumbnailView thumbnail = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail);
YouTubeThumbnailLoader loader = thumbnailViewToLoaderMap.get(thumbnail);
if (loader == null) {
// 2) The view is already created, and is currently being initialized. We store the
// current videoId in the tag.
thumbnail.setTag(entry.videoId);
} else {
// 3) The view is already created and already initialized. Simply set the right videoId
// on the loader.
thumbnail.setImageResource(R.drawable.loading_thumbnail);
loader.setVideo(entry.videoId);
}
}
TextView label = ((TextView) view.findViewById(R.id.text));
label.setText(entry.text);
label.setVisibility(labelsVisible ? View.VISIBLE : View.GONE);
return view;
}
private final class ThumbnailListener implements
YouTubeThumbnailView.OnInitializedListener,
YouTubeThumbnailLoader.OnThumbnailLoadedListener {
@Override
public void onInitializationSuccess(
YouTubeThumbnailView view, YouTubeThumbnailLoader loader) {
loader.setOnThumbnailLoadedListener(this);
thumbnailViewToLoaderMap.put(view, loader);
view.setImageResource(R.drawable.loading_thumbnail);
String videoId = (String) view.getTag();
loader.setVideo(videoId);
}
@Override
public void onInitializationFailure(
YouTubeThumbnailView view, YouTubeInitializationResult loader) {
view.setImageResource(R.drawable.no_thumbnail);
}
@Override
public void onThumbnailLoaded(YouTubeThumbnailView view, String videoId) {
}
@Override
public void onThumbnailError(YouTubeThumbnailView view, ErrorReason errorReason) {
view.setImageResource(R.drawable.no_thumbnail);
}
}
}
public static final class VideoFragment extends YouTubePlayerFragment
implements OnInitializedListener {
private YouTubePlayer player;
private String videoId;
public static VideoFragment newInstance() {
return new VideoFragment();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initialize(DeveloperKey.DEVELOPER_KEY, this);
}
@Override
public void onDestroy() {
if (player != null) {
player.release();
}
super.onDestroy();
}
public void setVideoId(String videoId) {
if (videoId != null && !videoId.equals(this.videoId)) {
this.videoId = videoId;
if (player != null) {
player.cueVideo(videoId);
}
}
}
public void pause() {
if (player != null) {
player.pause();
}
}
@Override
public void onInitializationSuccess(Provider provider, YouTubePlayer player, boolean restored) {
this.player = player;
player.addFullscreenControlFlag(YouTubePlayer.FULLSCREEN_FLAG_CUSTOM_LAYOUT);
player.setOnFullscreenListener((VideoListDemoActivity) getActivity());
if (!restored && videoId != null) {
player.cueVideo(videoId);
}
}
@Override
public void onInitializationFailure(Provider provider, YouTubeInitializationResult result) {
this.player = null;
}
}
private static final class VideoEntry {
private final String text;
private final String videoId;
public VideoEntry(String text, String videoId) {
this.text = text;
this.videoId = videoId;
}
}
// Utility methods for layouting.
private int dpToPx(int dp) {
return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
}
private static void setLayoutSize(View view, int width, int height) {
LayoutParams params = view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
private static void setLayoutSizeAndGravity(View view, int width, int height, int gravity) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
params.gravity = gravity;
view.setLayoutParams(params);
}
}
一切都按预期进行,直到我点击其中一个要观看的视频并且应用程序崩溃:
12-25 10:14:27.418: D/AbsListView(13958): Get MotionRecognitionManager
12-25 10:14:27.608: D/libEGL(13958): loaded /system/lib/egl/libEGL_mali.so
12-25 10:14:27.633: D/libEGL(13958): loaded /system/lib/egl/libGLESv1_CM_mali.so
12-25 10:14:27.638: D/libEGL(13958): loaded /system/lib/egl/libGLESv2_mali.so
12-25 10:14:27.663: D/(13958): Device driver API match
12-25 10:14:27.663: D/(13958): Device driver API version: 10
12-25 10:14:27.663: D/(13958): User space API version: 10
12-25 10:14:27.663: D/(13958): mali: REVISION=Linux-r2p4-02rel0 BUILD_DATE=Thu Oct 25 08:43:05 KST 2012
12-25 10:14:27.723: D/OpenGLRenderer(13958): Enabling debug mode 0
12-25 10:14:31.478: W/ResourceType(13958): Failure getting entry for 0x010802c0 (t=7 e=704) in package 0 (error -75)
12-25 10:14:31.568: D/dalvikvm(13958): GC_CONCURRENT freed 118K, 13% free 9721K/11143K, paused 16ms+23ms, total 88ms
12-25 10:14:33.153: D/dalvikvm(13958): GC_CONCURRENT freed 241K, 14% free 9932K/11463K, paused 12ms+12ms, total 52ms
12-25 10:14:33.233: D/AbsListView(13958): Get MotionRecognitionManager
12-25 10:14:33.313: D/dalvikvm(13958): GC_CONCURRENT freed 480K, 16% free 9956K/11783K, paused 12ms+3ms, total 30ms
12-25 10:14:33.398: D/dalvikvm(13958): GC_FOR_ALLOC freed 61K, 16% free 9979K/11783K, paused 21ms, total 23ms
12-25 10:14:33.398: I/dalvikvm-heap(13958): Grow heap (frag case) to 11.140MB for 144160-byte allocation
12-25 10:14:33.413: D/dalvikvm(13958): GC_FOR_ALLOC freed 1K, 16% free 10118K/11975K, paused 13ms, total 13ms
12-25 10:14:33.538: E/SpannableStringBuilder(13958): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
12-25 10:14:33.538: E/SpannableStringBuilder(13958): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
12-25 10:14:34.078: D/dalvikvm(13958): GC_CONCURRENT freed 247K, 14% free 10372K/11975K, paused 12ms+4ms, total 35ms
12-25 10:14:34.223: D/dalvikvm(13958): GC_CONCURRENT freed 252K, 14% free 10629K/12231K, paused 13ms+13ms, total 59ms
12-25 10:14:34.333: W/dalvikvm(13958): Unable to resolve superclass of Lcom/google/android/apps/youtube/core/player/overlay/bm; (844)
12-25 10:14:34.333: W/dalvikvm(13958): Link of class 'Lcom/google/android/apps/youtube/core/player/overlay/bm;' failed
12-25 10:14:34.333: E/dalvikvm(13958): Could not find class 'com.google.android.apps.youtube.core.player.overlay.bm', referenced from method com.google.android.apps.youtube.core.player.overlay.SubtitlesPreferences.<init>
12-25 10:14:34.333: W/dalvikvm(13958): VFY: unable to resolve new-instance 3657 (Lcom/google/android/apps/youtube/core/player/overlay/bm;) in Lcom/google/android/apps/youtube/core/player/overlay/SubtitlesPreferences;
12-25 10:14:34.333: D/dalvikvm(13958): VFY: replacing opcode 0x22 at 0x0019
12-25 10:14:34.333: E/dalvikvm(13958): Could not find class 'android.view.accessibility.CaptioningManager', referenced from method com.google.android.apps.youtube.core.player.overlay.SubtitlesPreferences.c
12-25 10:14:34.333: W/dalvikvm(13958): VFY: unable to resolve check-cast 845 (Landroid/view/accessibility/CaptioningManager;) in Lcom/google/android/apps/youtube/core/player/overlay/SubtitlesPreferences;
12-25 10:14:34.333: D/dalvikvm(13958): VFY: replacing opcode 0x1f at 0x000c
12-25 10:14:34.333: W/dalvikvm(13958): VFY: unable to find class referenced in signature (Landroid/view/accessibility/CaptioningManager;)
12-25 10:14:34.338: W/dalvikvm(13958): VFY: unable to find class referenced in signature (Landroid/view/accessibility/CaptioningManager;)
12-25 10:14:34.338: I/dalvikvm(13958): Could not find method android.view.accessibility.CaptioningManager.getFontScale, referenced from method com.google.android.apps.youtube.core.player.overlay.SubtitlesPreferences.a
12-25 10:14:34.338: W/dalvikvm(13958): VFY: unable to resolve virtual method 5865: Landroid/view/accessibility/CaptioningManager;.getFontScale ()F
12-25 10:14:34.338: D/dalvikvm(13958): VFY: replacing opcode 0x6e at 0x000a
12-25 10:14:34.343: W/dalvikvm(13958): VFY: unable to find class referenced in signature (Landroid/view/accessibility/CaptioningManager;)
12-25 10:14:34.343: I/dalvikvm(13958): Could not find method android.view.accessibility.CaptioningManager.getUserStyle, referenced from method com.google.android.apps.youtube.core.player.overlay.SubtitlesPreferences.b
12-25 10:14:34.343: W/dalvikvm(13958): VFY: unable to resolve virtual method 5866: Landroid/view/accessibility/CaptioningManager;.getUserStyle ()Landroid/view/accessibility/CaptioningManager$CaptionStyle;
12-25 10:14:34.343: D/dalvikvm(13958): VFY: replacing opcode 0x6e at 0x000c
12-25 10:14:34.343: W/dalvikvm(13958): Unable to resolve superclass of Lcom/google/android/apps/youtube/core/player/overlay/bm; (844)
12-25 10:14:34.343: W/dalvikvm(13958): Link of class 'Lcom/google/android/apps/youtube/core/player/overlay/bm;' failed
12-25 10:14:34.343: D/dalvikvm(13958): DexOpt: unable to opt direct call 0x5b51 at 0x1c in Lcom/google/android/apps/youtube/core/player/overlay/SubtitlesPreferences;.<init>
12-25 10:14:34.343: W/dalvikvm(13958): VFY: unable to resolve instance field 1850
12-25 10:14:34.343: D/dalvikvm(13958): VFY: replacing opcode 0x52 at 0x0003
12-25 10:14:34.343: I/dalvikvm(13958): DexOpt: unable to optimize instance field ref 0x073b at 0x07 in Lcom/google/android/apps/youtube/core/model/SubtitlesStyle;.<init>
12-25 10:14:34.343: I/dalvikvm(13958): DexOpt: unable to optimize instance field ref 0x073c at 0x0b in Lcom/google/android/apps/youtube/core/model/SubtitlesStyle;.<init>
12-25 10:14:34.348: I/dalvikvm(13958): DexOpt: unable to optimize instance field ref 0x073d at 0x0f in Lcom/google/android/apps/youtube/core/model/SubtitlesStyle;.<init>
12-25 10:14:34.398: D/dalvikvm(13958): GC_CONCURRENT freed 154K, 12% free 10942K/12423K, paused 12ms+3ms, total 40ms
12-25 10:14:35.993: D/dalvikvm(13958): GC_FOR_ALLOC freed 235K, 14% free 10953K/12679K, paused 24ms, total 24ms
12-25 10:14:35.993: I/dalvikvm-heap(13958): Grow heap (frag case) to 12.201MB for 259216-byte allocation
12-25 10:14:36.013: D/dalvikvm(13958): GC_FOR_ALLOC freed 1K, 14% free 11204K/12935K, paused 21ms, total 21ms
12-25 10:14:36.053: D/dalvikvm(13958): GC_FOR_ALLOC freed 1K, 14% free 11204K/12935K, paused 20ms, total 20ms
12-25 10:14:36.053: I/dalvikvm-heap(13958): Grow heap (frag case) to 12.447MB for 259216-byte allocation
12-25 10:14:36.073: D/dalvikvm(13958): GC_FOR_ALLOC freed <1K, 14% free 11457K/13191K, paused 21ms, total 21ms
12-25 10:14:36.148: D/dalvikvm(13958): GC_FOR_ALLOC freed 1K, 13% free 11711K/13447K, paused 26ms, total 27ms
12-25 10:14:36.178: D/dalvikvm(13958): GC_FOR_ALLOC freed 1K, 13% free 11965K/13703K, paused 18ms, total 18ms
12-25 10:14:45.913: D/AndroidRuntime(13958): Shutting down VM
12-25 10:14:45.913: W/dalvikvm(13958): threadid=1: thread exiting with uncaught exception (group=0x418562a0)
12-25 10:14:45.928: E/AndroidRuntime(13958): FATAL EXCEPTION: main
12-25 10:14:45.928: E/AndroidRuntime(13958): java.lang.NullPointerException
12-25 10:14:45.928: E/AndroidRuntime(13958): at com.examples.youtubeapidemo.VideoListDemoActivity$VideoListFragment.onListItemClick(VideoListDemoActivity.java:337)
12-25 10:14:45.928: E/AndroidRuntime(13958): at android.app.ListFragment$2.onItemClick(ListFragment.java:160)
12-25 10:14:45.928: E/AndroidRuntime(13958): at android.widget.AdapterView.performItemClick(AdapterView.java:301)
12-25 10:14:45.928: E/AndroidRuntime(13958): at android.widget.AbsListView.performItemClick(AbsListView.java:1280)
12-25 10:14:45.928: E/AndroidRuntime(13958): at android.widget.AbsListView$PerformClick.run(AbsListView.java:3071)
12-25 10:14:45.928: E/AndroidRuntime(13958): at android.widget.AbsListView$1.run(AbsListView.java:3973)
12-25 10:14:45.928: E/AndroidRuntime(13958): at android.os.Handler.handleCallback(Handler.java:615)
12-25 10:14:45.928: E/AndroidRuntime(13958): at android.os.Handler.dispatchMessage(Handler.java:92)
12-25 10:14:45.928: E/AndroidRuntime(13958): at android.os.Looper.loop(Looper.java:137)
12-25 10:14:45.928: E/AndroidRuntime(13958): at android.app.ActivityThread.main(ActivityThread.java:4921)
12-25 10:14:45.928: E/AndroidRuntime(13958): at java.lang.reflect.Method.invokeNative(Native Method)
12-25 10:14:45.928: E/AndroidRuntime(13958): at java.lang.reflect.Method.invoke(Method.java:511)
12-25 10:14:45.928: E/AndroidRuntime(13958): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
12-25 10:14:45.928: E/AndroidRuntime(13958): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
12-25 10:14:45.928: E/AndroidRuntime(13958): at dalvik.system.NativeStart.main(Native Method)
12-25 10:14:57.303: I/Process(13958): Sending signal. PID: 13958 SIG: 9
我正在使用 Linux Slitaz 上的 eclipse IDE 在 Samsung Galaxy S3 (Android 4.1.2) 上测试该应用程序。
任何指导将不胜感激。
最佳答案
然后回答:
需要从AsyncTask中获取返回值,然后在onCreate方法中执行setContentView等代码! stackoverflow 是最好的!
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.examples.youtubeapidemo;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayer.OnFullscreenListener;
import com.google.android.youtube.player.YouTubePlayer.OnInitializedListener;
import com.google.android.youtube.player.YouTubePlayer.Provider;
import com.google.android.youtube.player.YouTubePlayerFragment;
import com.google.android.youtube.player.YouTubeThumbnailLoader;
import com.google.android.youtube.player.YouTubeThumbnailLoader.ErrorReason;
import com.google.android.youtube.player.YouTubeThumbnailView;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ListFragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.res.Configuration;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.TextView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* A sample Activity showing how to manage multiple YouTubeThumbnailViews in an adapter for display
* in a List. When the list items are clicked, the video is played by using a YouTubePlayerFragment.
* <p>
* The demo supports custom fullscreen and transitioning between portrait and landscape without
* rebuffering.
*/
@TargetApi(13)
public final class VideoListDemoActivity extends Activity implements OnFullscreenListener {
/** The duration of the animation sliding up the video in portrait. */
private static final int ANIMATION_DURATION_MILLIS = 300;
/** The padding between the video list and the video in landscape orientation. */
private static final int LANDSCAPE_VIDEO_PADDING_DP = 5;
private VideoListFragment listFragment;
private VideoFragment videoFragment;
private View videoBox;
private View closeButton;
private boolean isFullscreen;
/*
*
* new code
*
*/
private static String url = "http://gdata.youtube.com/feeds/api/users/DayAndNightNewsChd/uploads?v=2&alt=jsonc";
public static List<VideoEntry> VIDEO_LIST;
public static List<VideoEntry> list = new ArrayList<VideoEntry>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
*
* execute asynctask to get the video list
*
*/
JSONParse myAsyncTask = new JSONParse();
// This must be called on UI thread:
myAsyncTask.execute();
// Calling this will block UI thread execution:
//ExecutionResult result = myAsyncTask.get();
//new JSONParse().execute();
try {
if (myAsyncTask.get() == true)
{
setContentView(R.layout.video_list_demo);
listFragment = (VideoListFragment) getFragmentManager().findFragmentById(R.id.list_fragment);
videoFragment =
(VideoFragment) getFragmentManager().findFragmentById(R.id.video_fragment_container);
closeButton = findViewById(R.id.close_button);
videoBox = findViewById(R.id.video_box);
videoBox.setVisibility(View.INVISIBLE);
layout();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
*
* AsyncTask
*
*/
private class JSONParse extends AsyncTask<Void, Void, Boolean>
{
private ProgressDialog pDialog;
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(VideoListDemoActivity.this);
pDialog.setMessage("Getting Data ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
@Override
protected Boolean doInBackground(Void... arg0) {
boolean status = false;
/*
*
*
* get the data from server and load it into the array
*
*
*/
try {
HttpClient client = new DefaultHttpClient();
HttpUriRequest request = new HttpGet(url);
HttpResponse response = client.execute(request);
String jsonString = StreamUtils.convertToString(response.getEntity().getContent());
JSONObject json = new JSONObject(jsonString);
JSONArray jsonArray = json.getJSONObject("data").getJSONArray("items");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String title = jsonObject.getString("title");
String video = jsonObject.getString("id");
//Log.d("YOUTUBE", title);
list.add(new VideoEntry(title, video));
}
} catch (ClientProtocolException e) {
//Log.e("Feck", e);
} catch (IOException e) {
//Log.e("Feck", e);
} catch (JSONException e) {
//Log.e("Feck", e);
}
VIDEO_LIST = Collections.unmodifiableList(list);
status = true;
return status;
}
@Override
protected void onPostExecute(Boolean result) {
/*
*
*
* this should be done in the oncreate() but causes app to crash
*
*
*/
pDialog.dismiss();
}
}//end async
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
layout();
}
@Override
public void onFullscreen(boolean isFullscreen) {
this.isFullscreen = isFullscreen;
layout();
}
/**
* Sets up the layout programatically for the three different states. Portrait, landscape or
* fullscreen+landscape. This has to be done programmatically because we handle the orientation
* changes ourselves in order to get fluent fullscreen transitions, so the xml layout resources
* do not get reloaded.
*/
private void layout() {
boolean isPortrait =
getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
listFragment.getView().setVisibility(isFullscreen ? View.GONE : View.VISIBLE);
listFragment.setLabelVisibility(isPortrait);
closeButton.setVisibility(isPortrait ? View.VISIBLE : View.GONE);
if (isFullscreen) {
videoBox.setTranslationY(0); // Reset any translation that was applied in portrait.
setLayoutSize(videoFragment.getView(), MATCH_PARENT, MATCH_PARENT);
setLayoutSizeAndGravity(videoBox, MATCH_PARENT, MATCH_PARENT, Gravity.TOP | Gravity.LEFT);
} else if (isPortrait) {
setLayoutSize(listFragment.getView(), MATCH_PARENT, MATCH_PARENT);
setLayoutSize(videoFragment.getView(), MATCH_PARENT, WRAP_CONTENT);
setLayoutSizeAndGravity(videoBox, MATCH_PARENT, WRAP_CONTENT, Gravity.BOTTOM);
} else {
videoBox.setTranslationY(0); // Reset any translation that was applied in portrait.
int screenWidth = dpToPx(getResources().getConfiguration().screenWidthDp);
setLayoutSize(listFragment.getView(), screenWidth / 4, MATCH_PARENT);
int videoWidth = screenWidth - screenWidth / 4 - dpToPx(LANDSCAPE_VIDEO_PADDING_DP);
setLayoutSize(videoFragment.getView(), videoWidth, WRAP_CONTENT);
setLayoutSizeAndGravity(videoBox, videoWidth, WRAP_CONTENT,
Gravity.RIGHT | Gravity.CENTER_VERTICAL);
}
}
@SuppressLint("NewApi")
public void onClickClose(@SuppressWarnings("unused") View view) {
listFragment.getListView().clearChoices();
listFragment.getListView().requestLayout();
videoFragment.pause();
videoBox.animate()
.translationYBy(videoBox.getHeight())
.setDuration(ANIMATION_DURATION_MILLIS)
.withEndAction(new Runnable() {
@Override
public void run() {
videoBox.setVisibility(View.INVISIBLE);
}
});
}
/**
* A fragment that shows a static list of videos.
*/
public static final class VideoListFragment extends ListFragment {
/*
private static final List<VideoEntry> VIDEO_LIST;
static {
List<VideoEntry> list = new ArrayList<VideoEntry>();
list.add(new VideoEntry("YouTube Collection", "Y_UmWdcTrrc"));
list.add(new VideoEntry("GMail Tap", "1KhZKNZO8mQ"));
list.add(new VideoEntry("Chrome Multitask", "UiLSiqyDf4Y"));
list.add(new VideoEntry("Google Fiber", "re0VRK6ouwI"));
list.add(new VideoEntry("Autocompleter", "blB_X38YSxQ"));
list.add(new VideoEntry("GMail Motion", "Bu927_ul_X0"));
list.add(new VideoEntry("Translate for Animals", "3I24bSteJpw"));
VIDEO_LIST = Collections.unmodifiableList(list);
}
*/
private PageAdapter adapter;
private View videoBox;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//new JSONParse().execute();
adapter = new PageAdapter(getActivity(), VIDEO_LIST);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
videoBox = getActivity().findViewById(R.id.video_box);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
setListAdapter(adapter);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
String videoId = VIDEO_LIST.get(position).videoId;
VideoFragment videoFragment =
(VideoFragment) getFragmentManager().findFragmentById(R.id.video_fragment_container);
videoFragment.setVideoId(videoId);
// The videoBox is INVISIBLE if no video was previously selected, so we need to show it now.
if (videoBox.getVisibility() != View.VISIBLE) {
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// Initially translate off the screen so that it can be animated in from below.
videoBox.setTranslationY(videoBox.getHeight());
}
videoBox.setVisibility(View.VISIBLE);
}
// If the fragment is off the screen, we animate it in.
if (videoBox.getTranslationY() > 0) {
videoBox.animate().translationY(0).setDuration(ANIMATION_DURATION_MILLIS);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
adapter.releaseLoaders();
}
public void setLabelVisibility(boolean visible) {
adapter.setLabelVisibility(visible);
}
}
/**
* Adapter for the video list. Manages a set of YouTubeThumbnailViews, including initializing each
* of them only once and keeping track of the loader of each one. When the ListFragment gets
* destroyed it releases all the loaders.
*/
private static final class PageAdapter extends BaseAdapter {
private final List<VideoEntry> entries;
private final List<View> entryViews;
private final Map<YouTubeThumbnailView, YouTubeThumbnailLoader> thumbnailViewToLoaderMap;
private final LayoutInflater inflater;
private final ThumbnailListener thumbnailListener;
private boolean labelsVisible;
public PageAdapter(Context context, List<VideoEntry> entries) {
this.entries = entries;
entryViews = new ArrayList<View>();
thumbnailViewToLoaderMap = new HashMap<YouTubeThumbnailView, YouTubeThumbnailLoader>();
inflater = LayoutInflater.from(context);
thumbnailListener = new ThumbnailListener();
labelsVisible = true;
}
public void releaseLoaders() {
for (YouTubeThumbnailLoader loader : thumbnailViewToLoaderMap.values()) {
loader.release();
}
}
public void setLabelVisibility(boolean visible) {
labelsVisible = visible;
for (View view : entryViews) {
view.findViewById(R.id.text).setVisibility(visible ? View.VISIBLE : View.GONE);
}
}
@Override
public int getCount() {
return entries.size();
}
@Override
public VideoEntry getItem(int position) {
return entries.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
VideoEntry entry = entries.get(position);
// There are three cases here
if (view == null) {
// 1) The view has not yet been created - we need to initialize the YouTubeThumbnailView.
view = inflater.inflate(R.layout.video_list_item, parent, false);
YouTubeThumbnailView thumbnail = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail);
thumbnail.setTag(entry.videoId);
thumbnail.initialize(DeveloperKey.DEVELOPER_KEY, thumbnailListener);
} else {
YouTubeThumbnailView thumbnail = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail);
YouTubeThumbnailLoader loader = thumbnailViewToLoaderMap.get(thumbnail);
if (loader == null) {
// 2) The view is already created, and is currently being initialized. We store the
// current videoId in the tag.
thumbnail.setTag(entry.videoId);
} else {
// 3) The view is already created and already initialized. Simply set the right videoId
// on the loader.
thumbnail.setImageResource(R.drawable.loading_thumbnail);
loader.setVideo(entry.videoId);
}
}
TextView label = ((TextView) view.findViewById(R.id.text));
label.setText(entry.text);
label.setVisibility(labelsVisible ? View.VISIBLE : View.GONE);
return view;
}
private final class ThumbnailListener implements
YouTubeThumbnailView.OnInitializedListener,
YouTubeThumbnailLoader.OnThumbnailLoadedListener {
@Override
public void onInitializationSuccess(
YouTubeThumbnailView view, YouTubeThumbnailLoader loader) {
loader.setOnThumbnailLoadedListener(this);
thumbnailViewToLoaderMap.put(view, loader);
view.setImageResource(R.drawable.loading_thumbnail);
String videoId = (String) view.getTag();
loader.setVideo(videoId);
}
@Override
public void onInitializationFailure(
YouTubeThumbnailView view, YouTubeInitializationResult loader) {
view.setImageResource(R.drawable.no_thumbnail);
}
@Override
public void onThumbnailLoaded(YouTubeThumbnailView view, String videoId) {
}
@Override
public void onThumbnailError(YouTubeThumbnailView view, ErrorReason errorReason) {
view.setImageResource(R.drawable.no_thumbnail);
}
}
}
public static final class VideoFragment extends YouTubePlayerFragment
implements OnInitializedListener {
private YouTubePlayer player;
private String videoId;
public static VideoFragment newInstance() {
return new VideoFragment();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initialize(DeveloperKey.DEVELOPER_KEY, this);
}
@Override
public void onDestroy() {
if (player != null) {
player.release();
}
super.onDestroy();
}
public void setVideoId(String videoId) {
if (videoId != null && !videoId.equals(this.videoId)) {
this.videoId = videoId;
if (player != null) {
player.cueVideo(videoId);
}
}
}
public void pause() {
if (player != null) {
player.pause();
}
}
@Override
public void onInitializationSuccess(Provider provider, YouTubePlayer player, boolean restored) {
this.player = player;
player.addFullscreenControlFlag(YouTubePlayer.FULLSCREEN_FLAG_CUSTOM_LAYOUT);
player.setOnFullscreenListener((VideoListDemoActivity) getActivity());
if (!restored && videoId != null) {
player.cueVideo(videoId);
}
}
@Override
public void onInitializationFailure(Provider provider, YouTubeInitializationResult result) {
this.player = null;
}
}
private static final class VideoEntry {
private final String text;
private final String videoId;
public VideoEntry(String text, String videoId) {
this.text = text;
this.videoId = videoId;
}
}
// Utility methods for layouting.
private int dpToPx(int dp) {
return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
}
private static void setLayoutSize(View view, int width, int height) {
LayoutParams params = view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
private static void setLayoutSizeAndGravity(View view, int width, int height, int gravity) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
params.gravity = gravity;
view.setLayoutParams(params);
}
}
关于java - Android YouTube API 演示 使用 AsyncTask 加载视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20767713/
我对此很陌生,我在这里的论坛上检查过答案,但我没有找到任何真正可以帮助我的答案。我正在尝试播放 res/raw 文件夹中的视频。到目前为止我已经设置了这段代码: MediaPlayer mp; @Ov
我可以播放一个视频剪辑,检测视频的结尾,然后创建一个表单,然后播放另一个视频剪辑。我的问题是,表单 react 不正确,我创建了带有提交按钮和两个单选按钮可供选择的表单。我希望让用户进行选择,验证响应
首先,我必须说我在web2py讨论组中看到过类似的内容,但我不太理解。 我使用 web2py 设置了一个数据库驱动的网站,其中的条目只是 HTML 文本。其中大多数将包含 img和/或video指向相
我正在尝试在视频 View 中播放 YouTube 视频。 我将 xml 布局如下: 代码是这样的: setContentView(R.layout.webview); VideoV
我正在开发一个需要嵌入其中的 youtube 视频播放器的 android 应用程序。我成功地从 API 获得了 RTSP 视频 URL,但是当我试图在我的 android 视频 View 中加载这个
我目前正在从事一个使用 YouTube API 的网络项目。 我完全不熟悉 API。所以每一行代码都需要付出很多努力。 使用以下代码,我可以成功检索播放列表中的项目: https://www.goog
是否可以仅使用视频 ID 和 key 使用 API V3 删除 youtube 视频?我不断收到有关“必需参数:部分”丢失的错误消息。我用服务器和浏览器 api 键试了一下这是我的代码: // $yo
所以我一直坚持这个大约一个小时左右,我就是无法让它工作。到目前为止,我一直在尝试从字符串中提取整个链接,但现在我觉得只获取视频 ID 可能更容易。 RegEx 需要从以下链接样式中获取 ID/URL,
var app = angular.module('speakout', []).config( function($sceDelegateProvider) {
我正在努力从 RSS 提要中阅读音频、视频新闻。我如何确定该 rss 是用于新闻阅读器还是用于音频或视频? 这是视频源:http://feeds.cbsnews.com/CBSNewsVideo 这是
利用python反转图片/视频 准备:一张图片/一段视频 python库:pillow,moviepy 安装库 ?
我希望在用户双击视频区域时让我的视频全屏显示,而不仅仅是在他们单击控件中的小图标时。有没有办法添加事件或其他东西来控制用户点击视频时发生的情况? 谢谢! 最佳答案 按照 Musa 的建议,附
关闭。这个问题需要更多 focused .它目前不接受答案。 想改进这个问题?更新问题,使其仅关注一个问题 editing this post . 7年前关闭。 Improve this questi
我有一个公司培训视频加载到本地服务器上。我正在使用 HTML5 的视频播放来观看这些视频。该服务器无法访问网络,但我已加载 apache 并且端口 8080 对同一网络上的所有机器开放。 这些文件位于
我想混合来自 video.mp4 的视频(时长 1 分钟)和来自 audio.mp3 的音频(10 分钟持续时间)到一个持续时间为 1 分钟的输出文件中。来自 audio.mp3 的音频应该是从 4
关闭。这个问题需要更多 focused .它目前不接受答案。 想改进这个问题?更新问题,使其仅关注一个问题 editing this post . 8年前关闭。 Improve this questi
我正在尝试使用 peer/getUserMedia 创建一个视频 session 网络应用程序。 目前,当我将唯一 ID 发送到视频 session 时,我能够听到/看到任何加入我的 session
考虑到一段时间内的观看次数,我正在评估一种针对半自动脚本的不同方法,该脚本将对视频元数据执行操作。 简而言之,只要视频达到指标中的某个阈值,就说观看次数,它将触发某些操作。 现在要执行此操作,我将不得
我正在通过iBooks创建专门为iPad创建动态ePub电子书的网站。 它需要支持youtube视频播放,所以当我知道视频的直接路径时,我正在使用html5 标记。 有没有一种使用html5 标签嵌入
我对Android不熟悉,我想浏览youtube.com并在Webview内从网站显示视频。当前,当我尝试执行此操作时,将出现设备的浏览器,并让我使用设备浏览器浏览该站点。如果Webview不具备这种
我是一名优秀的程序员,十分优秀!