【问题标题】:Execute code right after a fragment becomes visible for the first time在片段第一次可见后立即执行代码
【发布时间】:2015-11-29 11:10:46
【问题描述】:

我有一个显示使用 MPAndroidChart 创建的折线图的片段。加载片段大约需要 200 毫秒。

我想通过在片段可见后立即加载图表数据数据来提高感知的应用程序性能。

因此,我需要在片段可见后立即执行代码,但仅在第一次可见时执行。

我不能使用 onResume(),因为它在片段可见之前被调用。

注意:我不能使用异步任务,它需要在 UI 线程上完成。

【问题讨论】:

  • 你是说不能把代码放到Fragment的onResume或者Activity的onResume
  • 目前代码在片段的onCreateView()中。无论如何我都不能使用 onResume(),无论是活动,还是片段的 onResume()。
  • 我不确定我是否理解您为什么不能使用 Fragment 的 onResume。该方法在 Fragment 变得可见后被调用。
  • 他希望它第一次执行。 onCreateView 是要走的路
  • 是的,但您始终可以创建一个标志,表明代码已经运行。

标签: android fragment lifecycle


【解决方案1】:
public class MyFragment extends Fragment{
  Boolean _areLecturesLoaded =false;
  @Override
  onCreateView(){
    //Inflate the required views. Code gets executed once View is made but not shown
    return v;
}
@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        //Code executes EVERY TIME user views the fragment

        if (isVisibleToUser && !_areLecturesLoaded ) {
            _areLecturesLoaded = true;
            // Code executes ONLY THE FIRST TIME fragment is viewed.
        }
    }
}

isVisisbleToUser 是内置的,当用户查看当前片段时为真。在用户第一次看到片段之前,它将保持为假。如果您希望每次用户查看片段时都执行一些代码,请将代码放在该区域但在 if 语句之外。

_areLecturesLoaded 被初始化为 false 并且一旦片段第一次被设置为 true 以确保将来不会调用 If 语句并且其中的代码只执行一次

视图小部件按钮等的所有初始化都必须在 onCreate() 中完成,以确保不会出现空指针和其他此类讨厌的异常。

【讨论】:

  • 谢谢,我试试看。
  • 如果您遇到任何问题,请告诉我。否则接受答案。谢谢
  • 不幸的是 setUserVisibleHint 从来没有接到过电话。我在 android 4.4 上使用日志对其进行了测试。也许它只有在我使用 viewpager 或其他东西时才有效。
  • 你要将片段附加到什么地方?这取决于这一点。我目前正在使用带有 viewpager 的片段。
  • 我只是使用片段管理器来加载它并把它放在backstack上。我从其他来源了解到,只要 viewpager-fragment 可见,viewpager 就会调用 setUserVisibleHint。但是在默认的fragment生命周期中似乎没有被调用...
【解决方案2】:

在 UI 线程上执行任何冗长的操作都是不好的做法 - 您将在处理期间阻塞整个 UI(因为只有一个 UI 线程)。而且 200 毫秒实际上很长,它是 1/5 秒,人眼很容易察觉到,假设您正在以 5 fps 的帧速率玩游戏。

感知的性能就是永远不会出现 UI 滞后。

使用AsyncTaskAsyncTaskLoader 处理您的数据,回调将在UI 线程上调用,所以不用担心。您可以通过将数据存储在例如成员变量中来控制它是否是一次性的。如果是null -- 加载,如果不是 -- 立即使用。

如果您的数据是相当静态的并且不是很大 - 在您的片段打开之前预加载它(例如,当 Activity 启动时,甚至在应用程序启动时)并在实例化时将数据传递给片段(通过Bundle 参数)。

【讨论】:

  • 我不能使用 AsyncTask,因为我需要在 UI 线程上初始化我的图表。 200 毫秒很长,但是没有这张图表,用户什么也做不了。因此我只能显示 200 毫秒的进度条。
  • 如果您花费了 200 毫秒的 UI 线程时间,您的进度条将被冻结。为什么需要在 UI 线程上处理?
  • 这是对的,但处理都是关于更新图表 UI。
  • 嗯,好吧,我可能看不到整个画面 :) 现在我有点好奇地想看看一些显示你在做什么的代码。
【解决方案3】:

它可以通过使用静态布尔变量来实现。我使用下面的代码仅在应用程序第一次启动时显示进度对话框。

public class SettingsFragment extends Fragment {

    static boolean _areLecturesLoaded = true;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_settings, container, false);

        return rootView;
    }

    private class Getlimits extends AsyncTask<Void, Void, Void> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pd = ProgressDialog.show(getActivity(), "", "Loading...", true);
            pd.setCancelable(false);
        }

        @Override
        protected Void doInBackground(Void... arg0) {
            //your background code
            if(_areLecturesLoaded) {
                try {
                    Thread.sleep(3500);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            return null;
        }
        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            // Dismiss the progress dialog
            if (pd.isShowing())
                pd.dismiss();
            _areLecturesLoaded = false;
        }
    }
}

【讨论】:

    【解决方案4】:

    定义和覆盖

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
    
    }
    

    然后把这两行放在onCreateView()函数中

          setUserVisibleHint(false);
          setUserVisibleHint(true);
    

    然后将你想要在片段开始处完成的代码放在 onStart() 函数中

    @Override
    public void onStart() {
        super.onStart();
         //your initial code is here.
    }
    

    【讨论】:

      【解决方案5】:

      放在 onViewCreated() 方法中。

      【讨论】:

      • 似乎是错误的事情。它甚至在 onResume() 之前被调用。 ->......“在 onCreateView(LayoutInflater, ViewGroup, Bundle) 返回后立即调用,但在任何保存的状态恢复到视图之前。但是,片段的视图层次结构此时并未附加到其父级。”
      猜你喜欢
      • 2011-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多