【问题标题】:Drawer + Tab + ViewPager and each fragment load data from serverDrawer + Tab + ViewPager 和每个片段从服务器加载数据
【发布时间】:2016-10-06 02:55:22
【问题描述】:

抽屉中的某些菜单将打开 Tab + ViewPager 内容。每个页面(片段)都是从服务器请求其数据的列表。

每次单击该菜单时,我希望内容会立即显示选项卡,即使仍然请求数据而不是空白屏幕。我尝试在 TabFragment 中添加进度条,以便在准备 ViewPager 和寻呼机数据时内容会显示加载。但是,内容仍然显示一个没有加载指示器的空白屏幕。我发现问题是因为从服务器请求数据的方法是从每个寻呼机调用的。

是否应该将请求数据的方法移到 TabFragment 中?

我的 TabFragment 类看起来像:

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    .....

    content = view.findViewById(R.id.content);
    content.setVisibility(View.GONE);
    tabLayout = (TabLayout) view.findViewById(R.id.tabs);
    viewPager = (ViewPager) view.findViewById(R.id.pager);

    progressBar = (ProgressBar) view.findViewById(R.id.progressBar1);

    farmerViewPagerAdapter = new FarmerViewPagerAdapter(getChildFragmentManager(), titles);
    viewPager.setOffscreenPageLimit(2);
    viewPager.setAdapter(farmerViewPagerAdapter);
        tabLayout.post(()->{
            tabLayout.setupWithViewPager(viewPager);
            for (int i = 0; i < titles.length; ++i){
                tabLayout.getTabAt(i).setIcon(icons[i]);
            }
        });
}

这里是每个页面的片段(每个页面请求不同的数据):

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    this.view = view;

    emptyView = view.findViewById(R.id.emptyView);
    emptyText = (TextView) view.findViewById(R.id.emptyTextView);

    recyclerView = (RecyclerView) view.findViewById(R.id.list);

    recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
    recyclerView.setItemAnimator(new DefaultItemAnimator());

    adapter = new FarmerAdapter(data, getContext());

    recyclerView.setAdapter(adapter);
    recyclerView.addItemDecoration(
            new HorizontalDividerItemDecoration.Builder(getContext())
                    .showLastDivider()
                    .marginResId(R.dimen.divider_margin_left, R.dimen.divider_margin_right)
                    .build());

    swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefreshLayout);
    swipeRefreshLayout.setOnRefreshListener(() -> {

                if (!Util.isNetworkAvailable(getContext())) {
                    if (swipeRefreshLayout.isRefreshing()) swipeRefreshLayout.setRefreshing(false);
                } else {
                    currentPage = 1;
                    loadData(); //method to request data from server
                }
            }
    );


    if (user != null) {
        getDataFromLocal();
        addToAdapter();
        loadData();
    }

}

(Ed)loadData 方法:

Observable<Response<List<Data>>> dataApi = request.getServerData(currentPage,
            NUMBER_DATA_PER_PAGE, 
            token);
    dataApi.subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(responseData -> {
                if (swipeRefreshLayout.isRefreshing()) swipeRefreshLayout.setRefreshing(false);
                if (responseData.isSuccessful() && responseData.code() == 200) {

                    currentPage++;

                    adapter.add(responseData.body());
                    if (adapter.getItemCount() < 1) {
                        emptyText.setText("Empty");
                        emptyView.setVisibility(View.VISIBLE);
                    }

                } else {
                    try {
                        JSONObject json = new JSONObject(responseFarmer.errorBody().string());
                        Toast.makeText(getContext(), json.getString("message"), Toast.LENGTH_LONG).show();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, error -> {
                if (swipeRefreshLayout != null && swipeRefreshLayout.isRefreshing())
                    swipeRefreshLayout.setRefreshing(false);
                if (error != null && error.getLocalizedMessage() != null)
                    Toast.makeText(getContext(), error.getLocalizedMessage(), Toast.LENGTH_LONG).show();
            });

这个方法是从分页片段中调用的。

【问题讨论】:

    标签: android android-fragments android-viewpager android-tablayout


    【解决方案1】:

    您的 AsyncTask 有一个空的 doInBackground() 主体。这基本上使它同步。假设你有这个 AsyncTask:

    private class SetAdapterTask extends AsyncTask<Void,Void,Void> {
    
        protected Void doInBackground(Void... params) {
                return null;
            }
    
            @Override
            protected void onPostExecute(Void result) {
                doPostExecute();
            }
    
            @Override
            protected void onPreExecute() {
                doPreExecute();
            }
        }
    

    你在你的代码中这样称呼它:

    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        .....
        new SetAdapterTask().execute();
    }
    

    但由于您的 AsyncTask 不会在后台执行任何操作,因此 postExecute 会在 preExecute 之后立即触发,从而使整个事情等同于:

    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        .....
        doPreExecute();
        doPostExecute();
    }
    

    换句话说,您让 ProgressBar 在 preExecute 中可见,然后立即在 postExecute 中消失。

    解决此问题的正确方法是将 ProgressBar 可见性设置移动到用于加载数据的 AsyncTask,我认为它位于 loadData() 中的某个位置。至于数据加载本身,如果没有看到加载数据的实际方法,很难说是哪里出了问题。

    【讨论】:

    • 我添加了 loadData 方法。 doInBackgroud() 是空的,因为我无法在 viewPager 上设置Adapter,在 TabLayout 上无法设置 setupWithViewPager。如果我不使用 asynctask 来设置 viewpager,抽屉会在内容更改为带有 viewpager 的选项卡之前冻结片刻。
    • 在将 getSupportFragmentManager() 更改为 getChildFragmentManager() 后,我不再需要 asynctask。问题还是一样,当我单击抽屉菜单时,工具栏标题立即更改,并且在所有请求(每个寻呼机中的加载数据)完成后内容仍然冻结和更改。我想要完成的是当我点击抽屉菜单时,即使所有请求仍在工作,内容也应该立即更改。
    • 如果它仍然相关:我对 observables 不是很熟悉,但在我看来问题是你没有在 adapter.add(responseData.body()) 之后调用 adapter.notifyDatasetChanged() ;添加 adapter.notifyDatasetChanged() 以刷新您的适配器并显示新添加的数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多