当我的应用程序运行并显示带有内部列表视图的选项卡时,我遇到了一种奇怪的情况。问题是一次加载不同选项卡的数据。但它应该看起来像只为当前选项卡加载数据,而不是为全部或部分选项卡加载数据。为什么会发生?
我的主要活动是标签创建和初始化: public class MainActivity extends SherlockFragmentActivity { TabHost mTabHost; ViewPager mViewPager; 标签适配器 mTabsAdapter; 捆绑练习、拉伸、热身、下身;
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.Theme_Sherlock); // Used for theme switching in samples
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
mTabHost = (TabHost) findViewById(android.R.id.tabhost);
mTabHost.setup();
mViewPager = (ViewPager) findViewById(R.id.pager);
mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);
excercises = new Bundle();
excercises.putString("category", "Android Application Development Tutorials");
mTabsAdapter.addTab(mTabHost.newTabSpec("Excercises").setIndicator("Excercises"), VideoListLoader.VideoListFragment.class, excercises);
stretching = new Bundle();
stretching.putString("category", "iPhone Development Tutorials");
mTabsAdapter.addTab(mTabHost.newTabSpec("Stretching").setIndicator("Stretching"), VideoListLoader.VideoListFragment.class, stretching);
warmUp = new Bundle();
warmUp.putString("category", "PHP Tutorials Playlist");
mTabsAdapter.addTab(mTabHost.newTabSpec("Warm Up").setIndicator("Warm Up"), VideoListLoader.VideoListFragment.class, warmUp);
lowerBody = new Bundle();
lowerBody.putString("category", "Algebra Tutorials Playlist");
mTabsAdapter.addTab(mTabHost.newTabSpec("Lower Body").setIndicator("Lower Body"), VideoListLoader.VideoListFragment.class, lowerBody);
if (savedInstanceState != null) {
mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("tab", mTabHost.getCurrentTabTag());
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host 0dp
* high (it is not shown) and the TabsAdapter supplies its own dummy view to
* show as the tab content. It listens to changes in tabs, and takes care of
* switch to the correct paged in the ViewPager whenever the selected tab
* changes.
*/
public static class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final TabHost mTabHost;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final String tag;
private final Class<?> clss;
private final Bundle args;
TabInfo(String _tag, Class<?> _class, Bundle _args) {
tag = _tag;
clss = _class;
args = _args;
}
}
static class DummyTabFactory implements TabHost.TabContentFactory {
private final Context mContext;
public DummyTabFactory(Context context) {
mContext = context;
}
@Override
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mTabHost = tabHost;
mViewPager = pager;
mTabHost.setOnTabChangedListener(this);
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
tabSpec.setContent(new DummyTabFactory(mContext));
String tag = tabSpec.getTag();
TabInfo info = new TabInfo(tag, clss, args);
mTabs.add(info);
mTabHost.addTab(tabSpec);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
@Override
public void onTabChanged(String tabId) {
int position = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(position);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
// Unfortunately when TabHost changes the current tab, it kindly
// also takes care of putting focus on it when not in touch mode.
// The jerk.
// This hack tries to prevent this from pulling focus out of our
// ViewPager.
TabWidget widget = mTabHost.getTabWidget();
int oldFocusability = widget.getDescendantFocusability();
widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
mTabHost.setCurrentTab(position);
widget.setDescendantFocusability(oldFocusability);
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
}
我的 VideoListLoader:公共类 VideoListLoader 扩展 SherlockFragmentActivity {
private static final String TAG = VideoListLoader.class.getName();
VideoListFragment list;
VideoListAdapter mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
list = new VideoListFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class VideoListFragment extends SherlockListFragment implements LoaderCallbacks<RESTLoader.RESTResponse>, OnItemClickListener, OnScrollListener {
private static final int LOADER_PLAYLIST_SEARCH = 0x1, LOADER_VIDEOS_SEARCH = 0x2;
VideoListAdapter mAdapter;
private static final String ARGS_URI = "net.neilgoodman.android.restloadertutorial.ARGS_URI";
private static final String ARGS_PARAMS = "net.neilgoodman.android.restloadertutorial.ARGS_PARAMS";
private static final String MAX_RESULTS = "30";
private int START_INDEX;
List<VideoEntry> playlists;
private String playlistID, category;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAdapter = new VideoListAdapter(getSherlockActivity());
setListAdapter(mAdapter);
mAdapter.clear();
setListShown(false);
getListView().setOnItemClickListener(this);
getListView().setOnScrollListener(this);
if (savedInstanceState != null) {
ParseVideoList pvl = savedInstanceState.getParcelable("list");
Log.e("Saved item: ", pvl.getArrList().get(2).getTitle());
playlists = pvl.getArrList();
mAdapter.setData(playlists);
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
} else {
Uri playlistSearchUri = Uri.parse("https://gdata.youtube.com/feeds/api/users/thenewboston/playlists");
Bundle params = new Bundle();
params.putString("max-results", "50");
params.putString("alt", "jsonc");
params.putString("v", "2");
Bundle args = new Bundle();
args.putParcelable(ARGS_URI, playlistSearchUri);
args.putParcelable(ARGS_PARAMS, params);
getLoaderManager().initLoader(LOADER_PLAYLIST_SEARCH, args, this);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
ParseVideoList pvl = new ParseVideoList();
pvl.setArrList(playlists);
outState.putParcelable("list", pvl);
}
@Override
public Loader<RESTLoader.RESTResponse> onCreateLoader(int id, Bundle args) {
if (args != null && args.containsKey(ARGS_URI) && args.containsKey(ARGS_PARAMS)) {
Uri action = args.getParcelable(ARGS_URI);
Bundle params = args.getParcelable(ARGS_PARAMS);
return new RESTLoader(getSherlockActivity(), RESTLoader.HTTPVerb.GET, action, params);
}
return null;
}
@Override
public void onLoadFinished(Loader<RESTLoader.RESTResponse> loader, RESTLoader.RESTResponse data) {
int code = data.getCode();
String json = data.getData();
// category = getSherlockActivity().getIntent().getExtras().getString("category"); category = getArguments().get("category").toString(); Log.e("当前类别:", category); Log.e("JSON:", json); switch (loader.getId()) { case LOADER_PLAYLIST_SEARCH: if (code == 200 && !json.equals("")) {
if (playlistID == null) {
playlistID = getPlaylistID(getSherlockActivity(), category, json);
}
if (playlistID != null) {
Uri videoSearchUri = Uri.parse("https://gdata.youtube.com/feeds/api/playlists/" + playlistID);
Bundle params = new Bundle();
params.putString("max-results", MAX_RESULTS);
params.putString("start-index", "1");
params.putString("alt", "jsonc");
params.putString("v", "2");
Bundle args = new Bundle();
args.putParcelable(ARGS_URI, videoSearchUri);
args.putParcelable(ARGS_PARAMS, params);
getLoaderManager().initLoader(LOADER_VIDEOS_SEARCH, args, this);
break;
} else {
Toast.makeText(getSherlockActivity(), "No such a playlist", Toast.LENGTH_SHORT);
}
}
break;
case LOADER_VIDEOS_SEARCH:
if (code == 200 && !json.equals("")) {
playlists = getVideoList(getSherlockActivity(), json);
mAdapter.setData(playlists);
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
} else {
Toast.makeText(getSherlockActivity(), "Failed to load data. Check your internet settings.", Toast.LENGTH_SHORT).show();
}
break;
}
}
@Override
public void onLoaderReset(Loader<RESTLoader.RESTResponse> loader) {
mAdapter.setData(null);
}
private static String getPlaylistID(FragmentActivity fragmentActivity, String pCategory, String json) {
final Context context = fragmentActivity;
String playlistID = null;
try {
JSONObject playlistsWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray playlists = playlistsWrapper.getJSONObject("data").getJSONArray("items");
for (int i = 0; i < playlists.length(); i++) {
JSONObject playlist = playlists.getJSONObject(i);
if (pCategory.compareToIgnoreCase(playlist.getString("title")) == 0) {
VideoEntry entry = new VideoEntry(playlist);
entry.wrapPlaylistID(context);
entry.wrapPlaylistTitle(context);
playlistID = entry.getPlaylistID();
break;
}
}
} catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
return playlistID;
}
private static List<VideoEntry> getVideoList(FragmentActivity fragmentActivity, String json) {
List<VideoEntry> playlistsList = new ArrayList<VideoEntry>();
final Context context = fragmentActivity;
try {
JSONObject playlistsWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray playlists = playlistsWrapper.getJSONObject("data").getJSONArray("items");
for (int i = 0; i < playlists.length(); i++) {
JSONObject playlist = playlists.getJSONObject(i);
VideoEntry entry = new VideoEntry(playlist);
entry.wrapID(context);
entry.wrapTitle(context);
entry.wrapThumbURL(context);
playlistsList.add(entry);
Log.e("PlaylistsList: ", playlistsList.get(i).getThumbURL());
}
} catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
return playlistsList;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
int last_pos = view.getLastVisiblePosition() + 10;
Log.e("Last_pos in onScroll: ", Integer.toString(last_pos));
if (last_pos == mAdapter.getCount() && last_pos >= Integer.valueOf(MAX_RESULTS)) {
START_INDEX = last_pos + 1;
Log.e("PID in onScroll:", playlistID);
Log.e("START_INDEX in onScroll:", Integer.toString(START_INDEX));
Uri videoSearchUri = Uri.parse("https://gdata.youtube.com/feeds/api/playlists/" + playlistID);
Bundle params = new Bundle();
params.putString("max-results", MAX_RESULTS);
params.putString("start-index", Integer.toString(START_INDEX));
params.putString("alt", "jsonc");
params.putString("v", "2");
Bundle args = new Bundle();
args.putParcelable(ARGS_URI, videoSearchUri);
args.putParcelable(ARGS_PARAMS, params);
getLoaderManager().restartLoader(LOADER_VIDEOS_SEARCH, args, this);
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Intent lVideoIntent = new Intent(null, Uri.parse("ytv://" +
// mAdapter.getItem(position).getVideoID()), getSherlockActivity(),
// OpenYouTubePlayerActivity.class);
// startActivity(lVideoIntent);
new VideoManager().DownloadFromUrl("https://www.dropbox.com/s/4ph6ibvqn3e5wzq/movie.mp4", "movie.mp4");
}
}
}
我的日志:
10-15 12:39:38.668: E/Current Category:(2397): Android Application Development Tutorials
10-15 12:39:38.673: E/JSON:(2397): {"apiVersion":"2.1","data":{"totalItems":54,"startIndex":1,"itemsPerPage":50,"items":blablabla ...........
10-15 12:39:39.873: E/Current Category:(2397): Android Application Development Tutorials
10-15 12:39:39.873: E/JSON:(2397): {"apiVersion":"2.1","data":{"id":"PL2F07DBCDCC01493A","author":"thenewboston","title":"blablabla ............
10-15 12:39:41.003: E/Current Category:(2397): iPhone Development Tutorials
10-15 12:39:41.008: E/JSON:(2397): {"apiVersion":"2.1","data":{"totalItems":54,"startIndex":1,"itemsPerPage":50,"items":[{"id":blalblabla ...................
10-15 12:39:42.243: E/Current Category:(2397): iPhone Development Tutorials
10-15 12:39:42.243: E/JSON:(2397): {"apiVersion":"2.1","data": {"id":"PL53038489615793F7","author":"thenewboston","title":"iPhone Development Tutorials","blalbla ..........
在这里您可以看到 2 个选项卡的加载数据,但我没有切换到另一个选项卡,仅在第一个选项卡加载必要的内容时等待,但它会为一个和第二个选项卡加载。有人可以解释一下它为什么会发生以及如何避免它吗?