0

当我的应用程序运行并显示带有内部列表视图的选项卡时,我遇到了一种奇怪的情况。问题是一次加载不同选项卡的数据。但它应该看起来像只为当前选项卡加载数据,而不是为全部或部分选项卡加载数据。为什么会发生?

我的主要活动是标签创建和初始化: public class MainActivity extends SherlockFragmentActivity { TabHost mTab​​Host; ViewPager mViewPager; 标签适配器 mTab​​sAdapter; 捆绑练习、拉伸、热身、下身;

@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 个选项卡的加载数据,但我没有切换到另一个选项卡,仅在第一个选项卡加载必要的内容时等待,但它会为一个和第二个选项卡加载。有人可以解释一下它为什么会发生以及如何避免它吗?

4

2 回答 2

0

默认情况下,ViewPager加载当前页面和直接向左和向右的页面。这样做是为了让您可以流畅地滑动页面。

如果您不希望发生这种情况,则不应使用ViewPager(或覆盖其功能)。如果您确实想使用ViewPager,您可以将您的片段逻辑放入onPageSelected()或在父活动中执行您的逻辑。这些选项中的最后一个可能是最好的。

还,

请注意,此类目前处于早期设计和开发阶段。该 API 可能会在以后的兼容性库更新中发生变化,需要在针对较新版本编译应用程序时更改应用程序的源代码。

我自己对示例代码有一些问题。

于 2012-12-12T21:27:56.217 回答
0

首先,为了调用mTabHost.setCurrentTabByTag(YOUR_TAG),每次切换标签之间必须有一定的延迟。但这不是一个好习惯,有人有更好的主意吗?

于 2014-12-29T08:07:51.100 回答