Нестационарные внутренние классы действительно содержат ссылку на их родительские классы. Проблема с созданием внутреннего класса Fragment non-static заключается в том, что вы всегда держите ссылку на операцию . The GarbageCollector не удалось найти Активность. Таким образом, вы можете «просочиться» Деятельность, если, например, меняется ориентация. Потому что Фрагмент все еще может жить и вставляется в новый Активность.
EDIT:
Поскольку некоторые люди спрашивали меня почему, например, я начал писать один, делая это, я нашел еще несколько проблем при использовании не статических фрагментов:
- Они не могут быть использованы в xml-файл, поскольку у них нет пустого конструктора (у них может быть пустой конструктор, но вы обычно создаете нестатические вложенные классы, делая
myActivityInstance.new Fragment()
, и это отличается от вызова только пустого конструктора)
- Они не могут b e повторно используется вообще, так как
FragmentManager
иногда вызывает этот пустой конструктор. Если вы добавили фрагмент в некоторые транзакции.
Так что для того, чтобы сделать мой пример работы мне пришлось добавить
wrongFragment.setRetainInstance(true);
линии, чтобы не делать аварии приложения об изменении ориентации.
Если вы выполните этот код, у вас будет активность с некоторыми текстовыми изображениями и 2 кнопками - кнопки увеличат счетчик. И Фрагменты показывают, какую ориентацию они считают своей деятельностью. В начале все работает правильно. Но после изменения ориентации экрана только первый фрагмент работает корректно - второй по-прежнему вызывает материал при его старой активности.
Мой класс активность:
package com.example.fragmenttest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
public class WrongFragmentUsageActivity extends Activity
{
private String mActivityOrientation="";
private int mButtonClicks=0;
private TextView mClickTextView;
private static final String WRONG_FRAGMENT_TAG = "WrongFragment" ;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE)
{
mActivityOrientation = "Landscape";
}
else if (orientation == Configuration.ORIENTATION_PORTRAIT)
{
mActivityOrientation = "Portrait";
}
setContentView(R.layout.activity_wrong_fragement_usage);
mClickTextView = (TextView) findViewById(R.id.clicksText);
updateClickTextView();
TextView orientationtextView = (TextView) findViewById(R.id.orientationText);
orientationtextView.setText("Activity orientation is: " + mActivityOrientation);
Fragment wrongFragment = (WrongFragment) getFragmentManager().findFragmentByTag(WRONG_FRAGMENT_TAG);
if (wrongFragment == null)
{
wrongFragment = new WrongFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.mainView, wrongFragment, WRONG_FRAGMENT_TAG);
ft.commit();
wrongFragment.setRetainInstance(true); // <-- this is important - otherwise the fragment manager will crash when readding the fragment
}
}
private void updateClickTextView()
{
mClickTextView.setText("The buttons have been pressed " + mButtonClicks + " times");
}
private String getActivityOrientationString()
{
return mActivityOrientation;
}
@SuppressLint("ValidFragment")
public class WrongFragment extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
LinearLayout result = new LinearLayout(WrongFragmentUsageActivity.this);
result.setOrientation(LinearLayout.VERTICAL);
Button b = new Button(WrongFragmentUsageActivity.this);
b.setText("WrongFragmentButton");
result.addView(b);
b.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
buttonPressed();
}
});
TextView orientationText = new TextView(WrongFragmentUsageActivity.this);
orientationText.setText("WrongFragment Activities Orientation: " + getActivityOrientationString());
result.addView(orientationText);
return result;
}
}
public static class CorrectFragment extends Fragment
{
private WrongFragmentUsageActivity mActivity;
@Override
public void onAttach(Activity activity)
{
if (activity instanceof WrongFragmentUsageActivity)
{
mActivity = (WrongFragmentUsageActivity) activity;
}
super.onAttach(activity);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
LinearLayout result = new LinearLayout(mActivity);
result.setOrientation(LinearLayout.VERTICAL);
Button b = new Button(mActivity);
b.setText("CorrectFragmentButton");
result.addView(b);
b.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
mActivity.buttonPressed();
}
});
TextView orientationText = new TextView(mActivity);
orientationText.setText("CorrectFragment Activities Orientation: " + mActivity.getActivityOrientationString());
result.addView(orientationText);
return result;
}
}
public void buttonPressed()
{
mButtonClicks++;
updateClickTextView();
}
}
Обратите внимание, что вы должны, вероятно, не отбрасывать деятельность в onAttach
, если вы хотите использовать фрагмент в различных видах деятельности - но здесь его работать на примере.
activity_wrong_fragement_usage.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".WrongFragmentUsageActivity"
android:id="@+id/mainView">
<TextView
android:id="@+id/orientationText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
<TextView
android:id="@+id/clicksText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
<fragment class="com.example.fragmenttest.WrongFragmentUsageActivity$CorrectFragment"
android:id="@+id/correctfragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
может показать код – rkmax
в общем его плохой практике игнорировать ворса. Это довольно умный инструмент. Попробуйте опубликовать свой код, чтобы получить ответ о том, как вы могли бы лучше работать. –
Вы проверили этот http://code.google.com/p/android/issues/detail?id=41800, чтобы узнать, что такое ValidFragment? Линт говорит, что: «Каждый фрагмент должен иметь пустой конструктор, поэтому он может быть создан» – sandrstar