조각 내부 클래스는 정적이어야합니다.
FragmentActivity
표시해야하는 내부 클래스 가있는 클래스가 있습니다 Dialog
. 그러나 나는 그것을 만들어야한다 static
. Eclipse는 @SuppressLint("ValidFragment")
. 그렇게하면 나쁜 스타일이며 가능한 결과는 무엇입니까?
public class CarActivity extends FragmentActivity {
//Code
@SuppressLint("ValidFragment")
public class NetworkConnectionError extends DialogFragment {
private String message;
private AsyncTask task;
private String taskMessage;
@Override
public void setArguments(Bundle args) {
super.setArguments(args);
message = args.getString("message");
}
public void setTask(CarActivity.CarInfo task, String msg) {
this.task = task;
this.taskMessage = msg;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(message).setPositiveButton("Go back", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
Intent i = new Intent(getActivity().getBaseContext(), MainScreen.class);
startActivity(i);
}
});
builder.setNegativeButton("Retry", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
startDownload();
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
startDownload()
Asynctask를 시작합니다.
비 정적 내부 클래스 는 부모 클래스에 대한 참조를 보유합니다. Fragment 내부 클래스를 비 정적으로 만드는 문제는 항상 Activity에 대한 참조를 보유한다는 것 입니다. GarbageCollector은 당신의 수집 할 수 없습니다 활동 . 예를 들어 방향이 변경되면 활동을 '누수'할 수 있습니다 . 때문에 조각은 여전히 살 수있는 새에 삽입됩니다 활동 .
편집하다:
어떤 사람들이 나에게 몇 가지 예제를 요청했기 때문에 하나를 작성하기 시작했지만이 작업을 수행하는 동안 정적이 아닌 Fragments를 사용할 때 더 많은 문제를 발견했습니다.
- 빈 생성자가 없기 때문에 xml 파일에서 사용할 수 없습니다 (빈 생성자를 가질 수 있지만 일반적으로 수행
myActivityInstance.new Fragment()
하여 비 정적 중첩 클래스를 인스턴스화 하며 이는 빈 생성자를 호출하는 것과 다릅니다) - 그것들은 전혀 재사용 할 수 없습니다-
FragmentManager
때때로는이 빈 생성자를 호출하기 때문입니다. 일부 트랜잭션에 조각 을 추가 한 경우 .
그래서 제 예제를 만들기 위해 저는
wrongFragment.setRetainInstance(true);
방향 변경시 앱 충돌을 일으키지 않는 선.
이 코드를 실행하면 일부 텍스트보기와 2 개의 버튼이있는 활동이 생깁니다. 버튼은 일부 카운터를 증가시킵니다. 그리고 Fragments는 자신의 활동이 가지고 있다고 생각하는 방향을 보여줍니다. 처음에는 모든 것이 올바르게 작동합니다. 그러나 화면 방향을 변경 한 후에는 첫 번째 조각 만 올바르게 작동합니다. 두 번째 조각은 여전히 이전 활동에서 항목을 호출하고 있습니다.
내 활동 클래스 :
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>
I won't talk about inner fragments, but more specifically about a DialogFragment defined within an activity because it's 99% of the case for this question.
From my point of view, I don't want my DialogFragment (your NetworkConnectionError) to be static because I want to be able to call variables or methods from my containing class (Activity) in it.
It won't be static, but I don't want to generate memoryLeaks either.
What is the solution?
Simple. When you go in onStop, ensure you kill your DialogFragment. It's as simple as that. The code looks like something like that:
public class CarActivity extends AppCompatActivity{
/**
* The DialogFragment networkConnectionErrorDialog
*/
private NetworkConnectionError networkConnectionErrorDialog ;
//... your code ...//
@Override
protected void onStop() {
super.onStop();
//invalidate the DialogFragment to avoid stupid memory leak
if (networkConnectionErrorDialog != null) {
if (networkConnectionErrorDialog .isVisible()) {
networkConnectionErrorDialog .dismiss();
}
networkConnectionErrorDialog = null;
}
}
/**
* The method called to display your dialogFragment
*/
private void onDeleteCurrentCity(){
FragmentManager fm = getSupportFragmentManager();
networkConnectionErrorDialog =(DeleteAlert)fm.findFragmentByTag("networkError");
if(networkConnectionErrorDialog ==null){
networkConnectionErrorDialog =new DeleteAlert();
}
networkConnectionErrorDialog .show(getSupportFragmentManager(), "networkError");
}
And that way you avoid memory leaks (because it's bad) and you insure you don't have a [expletive] static fragment that cannot access your activity's fields and methods. This is the good way to handle that problem, from my point of view.
If u develop it in android studio then no problem if you not give it as static.The project will run without any errors and at the time of generation of apk you will get Error :This fragment inner class should be static [ValidFragment]
Thats lint error, you are probably building with gradle, to disable aborting on errors, add:
lintOptions {
abortOnError false
}
to build.gradle.`
If you want to access the members of outer-class (Activity) and still not want to make members static in Activity (since fragment should be public static), you can do the override onActivityCreated
public static class MyFragment extends ListFragment {
private OuterActivityName activity; // outer Activity
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
activity = (OuterActivityName) getActivity();
...
activity.member // accessing the members of activity
...
}
add annotation before inner class
@SuppressLint("validFragment")
참고URL : https://stackoverflow.com/questions/15571010/fragment-inner-class-should-be-static
'Programing' 카테고리의 다른 글
Content-disposition을 사용하여 파일을 하드 드라이브에 강제로 다운로드하는 방법은 무엇입니까? (0) | 2020.11.05 |
---|---|
if 문의 조건 부분에서 변수를 정의합니까? (0) | 2020.11.05 |
서비스 / 팩토리에서 컨트롤러로 변수 바인딩 (0) | 2020.11.05 |
Android에서 외부 SD 카드에 쓰는 보편적 인 방법 (0) | 2020.11.05 |
인터페이스를 사용하는 이유는 무엇입니까? (0) | 2020.11.05 |