Android Activity 可重用性

Android Activity Reusability

我创建了一个可重复使用的 xml 布局,如下所示

我想在不同的活动中使用相同的组件,我想做的是创建扩展 Activity.

BaseActivityClass
public class BaseActivityClass extends Activity {
    int layout_id = R.layout.SomeLayout;
    final int menu_button_id = R.id.menuButton;
    final int save_button_id = R.id.saveButton;

    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(layout_id);

       Button btn = findViewById(menu_button_id);
       btn.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            //this functionality will be same on every child class
        }
       });
   }
}

我想将 class 扩展为

public class SomeActivityClass extends BaseActivityClass {
    int layout_id = R.layout.SomeOtherLayout;

    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
    }
}

没有用于 Activity.On 意图调用的构造函数 class 仅引用了 class 名称。 并且 subclass 不能改变 super class 变量(隐藏)。

我不想将 BaseActivityClass 中的相同代码复制粘贴到其他 class 中。 包装器 class 可能会解决问题,但在我看来这太草率了。

我该如何解决这个设计问题? 我可以自由评论任何想法

听起来你希望 base class 控制主容器布局并允许 derived class 以提供 "content" 布局。那是对的吗?如果是这样,您可以使用此模式:

第 1 步 - 添加 ViewStub 到您的基本布局。一些伪代码给你的想法:

<ConstraintLayout>
   <!-- Common Stuff -->
   <Button id="menu">
   <Button id="save">

   <!-- "Content" area to be filled by derived classes -->
   <ViewStub id="viewStub" />

</ConstraintLayout>

第 2 步 - 更新您的基本布局以提供一种将内容填充到 "content area" 中的方法。一些伪代码:

public abstract class BaseActivityClass extends Activity {
    int layout_id = R.layout.SomeLayout;
    final int menu_button_id = R.id.menuButton;
    final int save_button_id = R.id.saveButton;

    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(layout_id);

       Button btn = findViewById(menu_button_id);
       btn.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            //this functionality will be same on every child class
        }
       });

       // Get the ViewStub, set the derived class's content layout on it and inflate it,
       // thereby displaying the derived class's view layout within the base class's 
       // "content area"
       ViewStub vs = findViewById(viewStub);
       vs.setLayout(getContentLayoutId());
       vs.inflate();
   }

   // Define abstract method that all derived classes must implement to provide
   // the id of the layout to show in the "content area"
   @LayoutRes
   public abstract int getContentLayoutId();
}

第 3 步 - 更新派生的 class 以提供要显示的布局。一些伪代码:

public class SomeActivityClass extends BaseActivityClass {
    int layout_id = R.layout.SomeOtherLayout;

    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
    }

    @Override
    @LayoutRes
    public int getContentLayoutId() { return layout_id; }
}

现在,当创建 SomeActivityClass 时,它会调用超级 class onCreate 来扩充您的基本布局,然后向派生的 class 询问其主要内容布局它推入 "content area".

我已经在我的项目中使用了这个模式并且效果很好。


另一种选择是通过超级 class 构造函数简单地传递布局 ID。如果基础 Activity 是 abstract 它将永远不会被实例化并且不必遵守零参数构造函数规则。只有您派生的 class 可以。所以你可以这样做:

public abstract class BaseActivityClass extends Activity {
    private final int mContentLayoutId;
    protected BaseActivityClass(int contentLayoutId) {
        mContentLayoutId = contentLayoutId;
    }

    protected void onCreate(Bundle state) {
        // Same code to load ViewStub, but use mContentLayoutId instead
    }
}

public SomeOtherActivity extends BaseActivity {
    public SomeOtherActivity() {
        super(R.layout.SomeOtherLayout); // Call super with derived layout
    }
}

希望对您有所帮助!