from stack overflow

and another chapter

I recently grew tired of constantly having to know String keys to pass arguments into Bundles when creating my Fragments. So I decided to make constructors for my Fragments that would take the parameters I wanted to set, and put those variables into the Bundles with the correct String keys, therefore eliminating the need for other Fragments and Activities needing to know those keys.

public ImageRotatorFragment() {
super();
Log.v(TAG, "ImageRotatorFragment()");
} public ImageRotatorFragment(int imageResourceId) {
Log.v(TAG, "ImageRotatorFragment(int imageResourceId)"); // Get arguments passed in, if any
Bundle args = getArguments();
if (args == null) {
args = new Bundle();
}
// Add parameters to the argument bundle
args.putInt(KEY_ARG_IMAGE_RES_ID, imageResourceId);
setArguments(args);
}

And then I pull out those arguments like normal.

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate"); // Set incoming parameters
Bundle args = getArguments();
if (args != null) {
mImageResourceId = args.getInt(KEY_ARG_IMAGE_RES_ID, StaticData.getImageIds()[0]);
}
else {
// Default image resource to the first image
mImageResourceId = StaticData.getImageIds()[0];
}
}

However, Lint took issue with this, saying not to have subclasses of Fragment with constructors with other parameters, requiring me to use @SuppressLint("ValidFragment") to even run the app. The thing is, this code works perfectly fine. I can use ImageRotatorFragment(int imageResourceId) or the old school method ImageRotatorFragment() and call setArguments() manually on it. When Android needs to recreate the Fragment (orientation change or low memory), it calls the ImageRotatorFragment() constructor and then passes the same argument Bundle with my values, which get set correctly.

So I have been searching for the "suggested" approach and see a lot of examples using newInstance() to create Fragments with parameters, which seems to do the same thing my constructor is. So I made my own to test it, and it works just as flawlessly as before, minus Lint whining about it.

public static ImageRotatorFragment newInstance(int imageResourceId) {
Log.v(TAG, "newInstance(int imageResourceId)"); ImageRotatorFragment imageRotatorFragment = new ImageRotatorFragment(); // Get arguments passed in, if any
Bundle args = imageRotatorFragment.getArguments();
if (args == null) {
args = new Bundle();
}
// Add parameters to the argument bundle
args.putInt(KEY_ARG_IMAGE_RES_ID, imageResourceId);
imageRotatorFragment.setArguments(args); return imageRotatorFragment;
}

I personally find that using constructors is a much more common practice than knowing to use newInstance() and passing parameters. I believe you can use this same constructor technique with Activities and Lint will not complain about it. So basically my question is, why does Google not want you to use constructors with parameters for Fragments?

My only guess is so you don't try to set an instance variable without using the Bundle, which won't get set when the Fragment gets recreated. By using a static newInstance() method, the compiler won't let you access an instance variable.

public ImageRotatorFragment(int imageResourceId) {
Log.v(TAG, "ImageRotatorFragment(int imageResourceId)"); mImageResourceId = imageResourceId;
}

I still don't feel like this is enough reason to disallow the use of parameters in constructors. Anyone else have insight into this?

1#

I personally find that using constructors is a much more common practice than knowing to use newInstance() and passing parameters.

The factory method pattern is used fairly frequently in modern software development.

So basically my question is, why does Google not want you to use constructors with parameters for Fragments?

You answered your own question:

My only guess is so you don't try to set an instance variable without using the Bundle, which won't get set when the Fragment gets recreated.

Correct.

I still don't feel like this is enough reason to disallow the use of parameters in constructors.

You are welcome to your opinion. You are welcome to disable this Lint check, either on a per-constructor or per-workspace fashion.

#2

EDIT: Although this works and can be useful, it is risky as private fields once set using this pattern maybe will not be retained when changing orientation and the references, usually from a previously viewed fragment, may be cleared by the system reclaiming memory. Using a bundle and making your objects parseable is advised.

I have come across a nice instantiation pattern using newInstance that means you don't have to call setArguments or getArguments which means you are not limited to just the data types you can set in a bundle.

Fragments need to have empty constructors to enable the system to re-instantiate and fragment constructors with parameters won't get called when re-instantiating the fragment. Hence using newInstance is a much better idea to actually add object references and data to your fragment instance.

I also don't really like using setArguments, getArguments. It is extra code and null checks and just seems restrictive as you can only set Parcelable's and primitive types. You also need extra boiler plate code to set up static key name strings etc etc...

So, you can achieve the same result but with viewer restrictions using newInstance like this:

private int resourceId;
private SomeView someView;
private OtherObject otherObject; // empty constructor to allow fragment re-instantiation
public ImageRotatorFragment() {} public static ImageRotatorFragment newInstance
(int resourceId, SomeView someView, OtherObject otherObject) {
ImageRotatorFragment fragment = new ImageRotatorFragment();
fragment.resourceId = resourceId;
fragment.someView = someView;
fragment.otherObject = otherObject;
return fragment;
}

If done this way, you can access the private member variables/fields of your fragment anywhere in your code with out have to call getArguments etc....

Hopefully this helps with writing cleaner more flexible code.

1.But... your private fields will be lost if the screen is rotated. Calling setArguments internally avoids that. The point of the question was what's the difference between using a constructor and a static newInstance. (Not much as far as I can see). Writing directly to private fields could equally be done using a constructor. –  Stuart Whitehouse

Ah, didn't realise that would happen. How then can you pass objects into fragments that are not primitive or parcelable and keep references to them? –  domji84 Sep 10 '13 at 11:28

2.I'm the wrong person to ask - that's why I found this question ;-) But AFAIK you'll need to bundle them somehow to either add them to the arguments or stored state of the fragment. In my case all I needed to actually do was store the ID of the object (a Guid which can be converted to/from a string) and that lets me recover the object from the data store if the activity is re-created. –  Stuart Whitehouse Sep 10 '13 at 14:03

3.@domji84 while this code will work when you first instantiate the Fragment. If the screen rotates or the Fragment is destroyed for memory needs, when it's recreated it will have it's empty constructor called and it will not set those instance variables again. This solution would only work if you also saved all of this state in onSaveInstanceState() and restored it in onCreate(), which means you still would have to use a Bundle. –  Steven Byle Sep 19 '13 at 13:32

public class TestFragment extends Fragment {
private static final String TAG = "TestFragment";
private String hello;// = "hello android";
private String defaultHello = "default value"; static TestFragment newInstance(String s) {
TestFragment newFragment = new TestFragment();
Bundle bundle = new Bundle();
bundle.putString("hello", s);
newFragment.setArguments(bundle);
return newFragment; } @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "TestFragment-----onCreate");
Bundle args = getArguments();
hello = args != null ? args.getString("hello") : defaultHello;
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
Log.d(TAG, "TestFragment-----onCreateView");
View view = inflater.inflate(R.layout.lay1, container, false);
TextView viewhello = (TextView) view.findViewById(R.id.tv_hello);
viewhello.setText(hello);
return view; } @Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "TestFragment-----onDestroy");
} }

Creating a Fragment: constructor vs newInstance()的更多相关文章

  1. listview,fragment结合起来

    这是csdn上的以个demo,很适合初学者.来源:http://download.csdn.net/detail/endlife99/7274419,侵删. MainActiviy: package ...

  2. Android Fragment 详解(未完...)

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. 之前写过一篇关于 Fragment 生命周期的文章 ...

  3. fragment的介绍与使用

    稍稍摘录一段Fragment.java中的说明文档. /** * A Fragment is a piece of an application's user interface or behavio ...

  4. 如何向一个Fragment传递参数---setArguments方法的介绍

    在我们平常开发中经常会用到Fragment,当我们使用Fragment时一般是通过new Fragment的构造方法来实现,如果我问你怎么向一个Fragment传递参数,你是不是会首先想到通过构造方法 ...

  5. java中new关键字和newInstance()方法有什么区别?

    1.new可以调用带参数的构造函数,newInstance不可以. 2.new 是 java 的关键字,用来构造一个类的实例.而 newInstance 是 Class 的一个方法,不过两个写法的效果 ...

  6. Fragment官方解析

    由于fragment和activity的生命周期很类似,对activity不熟悉的可以参考–深入了解Activity-生命周期, 深入理解Activity-任务,回退栈,启动模式, 概要 A Frag ...

  7. ViewPager+Fragment的结合使用,实现QQ界面的理解

    http://www.cssxt.com/html/2449/2449.html 效果如图: 实现代码解析:MainActivity.java1.引入布局文件2.4个标题控件的初始化以及点击事件的监听 ...

  8. Android Fragment详解(二):Fragment创建及其生命周期

    Fragments的生命周期 每一个fragments 都有自己的一套生命周期回调方法和处理自己的用户输入事件. 对应生命周期可参考下图: 创建片元(Creating a Fragment) To c ...

  9. Java中创建对象的5种方式 &&new关键字和newInstance()方法的区别

    转载:http://www.kuqin.com/shuoit/20160719/352659.html 用最简单的描述来区分new关键字和newInstance()方法的区别:newInstance: ...

随机推荐

  1. 【Floyd算法】Gym - 101572I - Import Spaghetti

    题意:有向图最小环,输出方案. #include<cstdio> #include<iostream> #include<string> #include<a ...

  2. Java并发(八):AbstractQueuedSynchronizer

    先做总结: 1.AbstractQueuedSynchronizer是什么? AbstractQueuedSynchronizer(AQS)这个抽象类,是Java并发包 java.util.concu ...

  3. JDK源码(1.7) -- java.util.AbstractCollection<E>

    java.util.AbstractCollection<E> 源码分析(JDK1.7) ------------------------------------------------- ...

  4. php -- php读取sqlserver中的datetime出现的格式问题

    php连接sqlserver2005时,读取出来的数据是01 15 2014 12:00AM, 也就是说日期的格式是MM DD YY hh:mmAM 那如何把它转变成24小时制,且显示的格式为YY-M ...

  5. VK Cup 2016 - Round 1 (Div. 2 Edition) B. Bear and Displayed Friends 树状数组

    B. Bear and Displayed Friends 题目连接: http://www.codeforces.com/contest/658/problem/B Description Lima ...

  6. 不错的VS2010扩展——JSEnhancements,让js和css也折叠

    在Visaul Studio 2010中写js或css代码,缺少像写C#代码时的那种折叠功能,当代码比较多时,就很不方便. 今天发现,已经有VS2010扩展支持这个功能,它就是——JSEnhancem ...

  7. 'NSUnknownKeyException', reason:....etValue:forUndefinedKey:]: this class is not key value coding-compliant for the key

    erminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MainTableViewControl ...

  8. 将dll文件注入到其他进程中的一种新方法

    http://www.45it.com/windowszh/201212/33946.htm http://www.hx95.cn/Article/OS/201212/65095.html 我们知道将 ...

  9. Android 开源项目android-open-project解析之(四) ColorPickView,GraphView,UI Style,Other

    十三.ColorPickView ColorPickerView 颜色选择器,支持PopupWindows或新的Activity中打开 项目地址:https://code.google.com/p/c ...

  10. HttpClient post提交数据,汉字转码

    public static String post(String url, String data) throws ClientProtocolException, IOException { Htt ...