【问题标题】:android:singleton instance not garbage collected after application is closedandroid:singleton 实例在应用程序关闭后不被垃圾收集
【发布时间】:2019-05-26 08:22:01
【问题描述】:

我有一个带有片段的 android 活动。

在片段中,我使用改造来获取数据并设置一个静态标志,这样,当我再次访问该片段时,我会再次限制获取数据。

我还将数据存储在单例实例中。

但即使在我销毁活动/关闭应用程序之后,静态标志和实例仍然可用,并且该列表也存在于实例中,这导致我的应用程序出现故障。

但我希望在每次运行时重新创建实例并获取数据。

这是我的单例实例。

public class Utilities {

    private static Utilities utils = null;

    private List<Data> friendsList;

    public List<Data> getDataList() {
        return dataList;
    }

    public void setDataList(List<Data> dataList) {
        this.dataList = dataList;
    }

    private List<Data> dataList;

    public synchronized static Utilities getInstance(){

        if(utils == null){
            utils = new Utilities();
        }
        return utils;
    }
}

这是我的片段:

public class DataFragment extends Fragment
{
    private static boolean hasObtainedData;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState)  {

        if(!hasObtainedData){
            getData(v);
        }else{
           recyclerView.setAdapter(new Adapter(utils.getDataList()));
         }
     }

     private void getData(View v) {

         //get Data using Retrofit:
         hasObtainedData = true;
         utils.setDataList(dataListObtainedUsingRetrofit)
         recyclerView.setAdapter(new Adapter(utils.getDataList()));
    } 
}

这就是我从 MainActivity 调用我的片段的方式:

@Override
public void onTabSelected(TabLayout.Tab tab) {
           getSupportFragmentManager().beginTransaction()
                            .replace(R.id.fragmentBox, new DataFragment()).commit();
    }    

我尝试在 MainActivity 的 onDestroy() 处提供 System.gc(),但仍然存在单例实例。

我基于此搜索了许多 SOF 帖子,但无法解决此问题。

任何帮助都会非常有用。

【问题讨论】:

  • 清除您在onDestroy() 中的活动列表如何?

标签: java android singleton fragment


【解决方案1】:

Utilities-Class 本身中指向 Singleton 的指针是静态的,因此 Singelton 永远无法用于 GC,除非您在离开 MainAcitivity 时设置 utils = null

Utilities.reset();

【讨论】:

  • 我试过了,但是布尔标志仍然存在,我如何在应用程序结束时重置!
  • 从布尔值中移除静态
  • 我获取了一次数据,当我转到其他片段并单击此 DataFragment 时,我不想再次获取数据。所以我将变量保持为静态。我应该如何在没有静态的情况下执行此操作?
  • 好的,然后在离开时也重置它;编写一个静态 DataFragment.reset()。或者更好的是,将标志移到 Utilities-Class 到 Singleton 中
  • 是的,这是唯一的解决方法,但是在 android 中使用静态变量是一种好习惯,尤其是在我的一次数据检索的情况下?我是否在 onTabSelected 中编写片段代码正确的方式?
【解决方案2】:

您的单例将无法在您的应用程序被终止后继续存在,并且可能发生的情况是您实际上并没有在测试期间完全杀死该应用程序。从您的控制台运行 adb shell am force-stop &lt;your-app-package&gt; 并查看是否仍然会导致问题。

话虽如此,如果您只希望您的数据在每次应用程序启动时运行一次,那么我建议您将其移至 ApplicationonCreate() 生命周期回调中

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //Begin process to fetch data and cache it here
    }
}

不要忘记将应用程序名称也添加到您的清单中,&lt;application android:name="your.packagename.App"

然后您根本不需要修改您的数据 - 每次应用程序启动时它只会运行一次。

但是,如果您真正想要的是每次启动 Activity 时更新您的数据,那么请执行与之前相同的过程,但在您的 Activity 中的 onCreate() 中。如果您希望在重新创建 Activity 时更新它,您也可以在 onDestroy() 中清除它:

@Override
public void onDestry() {
    super.onDestroy();
    Utilities.getInstance().setDataList(null);
}

此外,如果您的数据绑定到 Activity 的生命周期,那么您实际上不需要单例(绑定到应用程序的生命周期)。

【讨论】:

  • 感谢您的回答@PPartisan,我无法获得您对应用程序类部分的建议!是的,我只想获取一次数据。但它是在应用程序启动的第三个活动中。我该怎么办使用 Application 类获取数据?
  • 开始在应用程序的 onCreate 中填充数据/单例。这只会在每个应用程序启动时调用一次,这与您的 Activity 生命周期回调可能会被多次调用不同。
  • 应用程序生命周期何时执行?甚至在所有活动之前?
  • 是的 - 应用程序是在所有活动之前创建的。
  • 如果是这样,我将如何在我的应用程序类中执行我的改造数据获取。说,1)如果我想延迟加载我的数据 2)根据用户输入获取数据!在这种情况下,我可能无法在我的 Application 类中联网,对吗?只能获取静态 url 数据?
猜你喜欢
  • 2016-02-04
  • 1970-01-01
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-11
  • 1970-01-01
相关资源
最近更新 更多