草庐IT

android - fragment 内部类应该是静态的

coder 2023-05-08 原文

我有一个 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 无法收集您的Activity。因此,如果例如方向发生变化,您可以“泄露”Activity。因为 Fragment 可能仍然存在并被插入到一个新的 Activity 中。

编辑:

由于有人问我一些例子,我开始写一个,同时我在使用非静态 fragment 时发现了更多问题:

  • 它们不能在 xml 文件中使用,因为它们没有空构造函数(它们可以有空构造函数,但您通常通过执行 myActivityInstance.new Fragment() 和这与只调用一个空的构造函数不同)
  • 它们根本不能被重用——因为 FragmentManager 有时也会调用这个空的构造函数。如果您在某些事务中添加了 Fragment

因此,为了使我的示例正常工作,我必须添加

wrongFragment.setRetainInstance(true);

在方向改变时不会使应用崩溃的行。

如果您执行此代码,您将有一个带有一些 TextView 和 2 个按钮的 Activity - 这些按钮会增加一些计数器。 fragment 显示了他们认为他们的 Activity 所具有的方向。一开始一切正常。但是在更改屏幕方向后,只有第一个 Fragment 可以正常工作 - 第二个仍然在其旧 Activity 中调用东西。

我的 Activity 课:

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();
}

}

请注意,如果您想在不同的 Activity 中使用您的 Fragment,您可能不应该在 onAttach 中转换 Activity - 但在这里它适用于示例。

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>

关于android - fragment 内部类应该是静态的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15571010/

有关android - fragment 内部类应该是静态的的更多相关文章

  1. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  2. ruby - 是否可以从也在该模块中的类内部调用模块函数 - 2

    在这段Ruby代码中:ModuleMClassC当我尝试运行时出现“'M:Module'的未定义方法'helper'”错误c=M::C.new("world")c.work但直接从另一个类调用M::helper("world")工作正常。类不能调用在定义它们的同一模块中定义的模块函数吗?除了将类移出模块外,还有其他解决方法吗? 最佳答案 为了调用M::helper,你需要将它定义为defself.helper;结束为了进行比较,请查看以下修改后的代码段中的helper和helper2moduleMclassC

  3. ruby - 无法安装 gem - make 未被识别为内部或外部命令可运行程序或批处理文件 - 2

    我想在Windows7上安装带有ruby​​1.9.3的rspec-railsgem。我收到一些错误消息,提示无法安装某些json库。所以,我使用下面的说明来解决它。来源=The'json'nativegemrequiresinstalledbuildtools从[rubyinstaller.org][3]下载[Ruby1.9.3][2]从[rubyinstaller.org][3]下载DevKit文件对于Ruby1.9.3,使用[DevKit-tdm-32-4.5.2-20110712-1620-sfx.exe][4]将DevKit解压到路径C:\Ruby193\DevKit运行cd

  4. ruby - 如何在 Ruby 中实现私有(private)内部类 - 2

    来自Java,我正在尝试在Ruby中实现LinkedList。我在Java中实现它的通常方法是有一个名为LinkedList的类和一个名为Node的私有(private)内部类,其中LinkedList的每个对象都作为Node对象。classLinkedListprivateclassNodeattr_accessor:val,:nextendend我不想将Node类暴露给外部世界。然而,通过Ruby中的这个设置,我可以使用这个访问LinkedList类之外的私有(private)Node类对象-node=LinkedList::Node.new我知道,在Ruby1.9中,我们可以使用

  5. ruby - 如何在 Ruby 中只执行一次方法?有静态变量吗? - 2

    我写了一个脚本,其中包含一些方法定义,没有类和一些公共(public)代码。其中一些方法执行一些非常耗时的shell程序。然而,这些shell程序只需要在第一次调用该方法时执行。现在在C中,我会在每个方法中声明一个静态变量,以确保这些程序只执行一次。我怎么能在Ruby中做到这一点? 最佳答案 ruby中有一个成语:x||=y。defsomething@something||=calculate_somethingendprivatedefcalculate_something#somelongprocessend但是如果您的“长时间

  6. ruby-on-rails - Ruby 中的类方法(相当于 JAVA 中的静态方法) - 2

    伙计们,我正在学习ruby​​,最近从JAVA转行。在JAVA中,我可以将类的成员变量设为静态,并且该成员变量在类的实例中保持不变。我如何在ruby​​中实现相同的目标。我在我的ruby课上做了这样的事情:classBaseclass@@wordshashend到目前为止,这似乎在我测试时达到了目的,即@@wordhash在Baseclass的实例中保持不变。我的理解对吗?另外,我想在类中有一个成员方法,相当于JAVA中的静态方法(我不需要类的实例来访问它)。我怎样才能做到这一点?例如,我想在Baseclass中有一个像getwordshash()这样的方法,它返回@@wordshas

  7. ruby - 如何让模块 mixins 为静态方法工作? - 2

    假设我有两个模块。是否可以将一个模块包含在另一个模块中,使其表现得像一个混入?例如:moduleAdefself.fooputs"foo"barendendmoduleBincludeAdefself.barputs"bar"endendB.barB.foo编辑:我意识到我最初把代码抄错了。这些方法需要是静态的。更正后的代码在上面(但不起作用)。 最佳答案 如您所知,它不起作用,但为什么它不起作用是关于Ruby对象模型的非常好的一课。当你创建一个对象的实例时,你创建的是一个新对象,它有一组实例变量和一个指向对象类的指针(以及一些其他

  8. ruby - Lisp 作为内部 Ruby DSL? - 2

    我已经能够找到:a)用Ruby编写的Lisp解释器(即外部DSL)http://onestepback.org/index.cgi/Tech/Ruby/LispInRuby.redb)作为RubyDSL的Prologhttp://www.kdedevelopers.org/node/2369c)讨论Ruby“作为”一个Lisphttp://www.randomhacks.net/articles/2005/12/03/why-ruby-is-an-acceptable-lisp但奇怪的是,我实际上找不到Lisp的“内部”实现,例如Prolog的实现。我只是不够谷歌,还是还没有人发表过这

  9. ruby - RVM screen 内部损坏 - 2

    我正在使用screen,甚至在rvm1.9.2之后并且有一个合适的.rvmrc我的服务器将仍然使用jruby。我的.screenrc包含shell#{SHELL}rvm信息显示jruby。好像rvm1.9.2没有任何效果,但它在screen外工作正常。 最佳答案 好的,我找到了solution.创建一个.screenrc文件并将此代码段放入其中:shell-$SHELLofficialinstructions省略破折号。 关于ruby-RVMscreen内部损坏,我们在StackOver

  10. ruby - 使用 YARD for Ruby 文档的内部评论? - 2

    我正在将我维护的ruby​​gem从RDoc切换到YARD文档。但是,代码中有一些关键注释只需要保留在代码中,不应出现在文档中。例如:###SomeClassdocumentationhere.#--#CRITICALcommentthatshouldbeinthecodebutnotinthedocumentation,#andmustbeatthisparticularspotinthecode.#++#moredocumentationthatfollowsthecriticalcommentblock,butthispart#shouldbeinthegenerateddocu

随机推荐