3

在 Android 库中,FragmentActivity扩展了 Activity。我想添加一些方法,并覆盖原始Activity的一些方法。

import android.app.Activity

public class Activiti extends Activity {
    public void myNewMethod() { ... }
}

由于原始层次结构,FragmentActivity扩展了ActivitymyNewMethod()也应该出现在我的库中FragmentActiviti

import android.support.v4.app.FragmentActivity;

public abstract class FragmentActiviti extends FragmentActivity {
    public void myNewMethod() { ... }
}

但这会导致代码重复,我不希望这种情况发生。有没有办法避免这种重复?


编辑:使用场景

Activiti.java

public abstract class Activiti extends Activity {
    private int current_orientation = Configuration.ORIENTATION_UNDEFINED;  // ORIENTATION_UNDEFINED = 0

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        current_orientation = this.getResources().getConfiguration().orientation;
    }
    protected boolean isDevicePortrait() { return current_orientation == Configuration.ORIENTATION_PORTRAIT; }
}

FragmentActiviti.java

public abstract class FragmentActiviti extends FragmentActivity {
    /* This onCreate() can be omitted. Just putting here explicitly. */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    protected void someUtilsForFragments() { /* not used yet */ }
}

E_fragtest_06.java

public class E_fragtest_06 extends FragmentActiviti {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        System.out.printf(isDevicePortrait());      // this NOT WORK for now
    }
}

编辑 2:尝试使用 Util 类

我认为使用装饰器类将是解决这个问题的最好方法(不重复代码)。但是装饰器模式在 Android Activity 场景中应用有点困难(或不可能)。

我尝试实施@hazzik 的方法,但我仍然遇到一些问题。

ActivityUtil.java

public abstract class ActivityUtil {
    private int current_orientation = Configuration.ORIENTATION_UNDEFINED;  // ORIENTATION_UNDEFINED = 0

    public void onCreate(Activity activity, Bundle savedInstanceState) {
        activity.onCreate(savedInstanceState);
        current_orientation = activity.getResources().getConfiguration().orientation;
    }
    public boolean isDevicePortrait() { return current_orientation == Configuration.ORIENTATION_PORTRAIT; }
}

Activiti.java

public class Activiti extends Activity {
    private ActivityUtil activityUtil;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        activityUtil.onCreate(this, savedInstanceState);
    }
    protected boolean isDevicePortrait() { return activityUtil.isDevicePortrait(); }
}

FragmentActiviti.java

public abstract class FragmentActiviti extends FragmentActivity {
    private ActivityUtil activityUtil;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        activityUtil.onCreate(this, savedInstanceState);
    }
    protected boolean isDevicePortrait() { return activityUtil.isDevicePortrait(); }
}

ActivityUtil.onCreate()activity.onCreate(savedInstanceState);导致此编译错误:

Activity 类型的 onCreate(Bundle) 方法不可见。

如果我更改ActivityActiviti

public abstract class ActivityUtil {
    public void onCreate(Activiti activity, Bundle savedInstanceState) { ... }
    ...
}

这将导致FragmentActiviti.onCreate()'s中的另一个编译错误activityUtil.onCreate()

ActivityUtil 类型中的 onCreate(Activiti, Bundle) 方法不适用于参数 (FragmentActiviti, Bundle)

我理解为什么会发生这些错误。但我只是不知道如何避免它们。


感谢所有为这个问题做出贡献的人,特别是 @flup 指导我了解装饰器模式,@hazzik 和 @donramos 的广泛努力,我在这里发布

我的增强型 AndroidActivityFragmentActivity课程。

如果您也在开发 Android 应用程序,我希望我的代码可以在某些方面帮助你们:-)

ActivityCore.java

package xxx.android;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;

public final class ActivityCore {
    public interface ActivityCallbackInterface {
        public void onCreateCallback(Bundle savedInstanceState);
        public void onBeforeSaveInstanceState(Bundle outState);
        public void onSaveInstanceStateCallback(Bundle outState);
    }

    private final Activity activity;
    /**
     * This current_orientation variable should be once set, never changed during the object life-cycle.
     * But Activity.getResources() is not yet ready upon the object constructs.
     * That's why THIS CLASS is wholly responsible to maintain THIS VARIABLE UNCHANGED.
     */
    private int current_orientation = Configuration.ORIENTATION_UNDEFINED;  // ORIENTATION_UNDEFINED = 0

    public ActivityCore(Activity activity) { this.activity = activity; }

    public void onCreate(Bundle savedInstanceState) {
        ((ActivityCallbackInterface) activity).onCreateCallback(savedInstanceState);
        current_orientation = activity.getResources().getConfiguration().orientation;
    }

    public void onSaveInstanceState(Bundle outState) {
        /**
         * THIS is the best ever place i have found, to unload unwanted Fragments,
         * thus prevent re-creating of un-needed Fragments in the next state of Activity.
         *   (state e.g. Portrait-to-Landscape, or Landscape-to-Portrait)
         * 
         * The KEY is to do it BEFORE super.onSaveInstanceState()
         *   (my guess for this reason is, in super.onSaveInstanceState(),
         *    it saves the layout hierarchy, thus saved the Fragments into the Bundle also.
         *    Thus restored.
         *    Note that Fragments NOT IN LAYOUT, having ONLY TAGS, are also restored.)
         */
        ((ActivityCallbackInterface) activity).onBeforeSaveInstanceState(outState);
        ((ActivityCallbackInterface) activity).onSaveInstanceStateCallback(outState);
    }

    public int getCurrentOrientation() { return current_orientation; }

    public boolean isDevicePortrait() { return current_orientation == Configuration.ORIENTATION_PORTRAIT; }
    public boolean isDeviceLandscape() { return current_orientation == Configuration.ORIENTATION_LANDSCAPE; }
    public boolean isNewDevicePortrait() { return activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; }
    public boolean isNewDeviceLandscape() { return activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; }
    public boolean isPortrait2Landscape() { return isDevicePortrait() && isNewDeviceLandscape(); }
    public boolean isLandscape2Portrait() { return isDeviceLandscape() && isNewDevicePortrait(); }

    public String describeCurrentOrientation() { return describeOrientation(current_orientation); }
    public String getCurrentOrientationTag() { return getOrientationTag(current_orientation); }
    public String describeNewOrientation() { return describeOrientation(activity.getResources().getConfiguration().orientation); }
    public String getNewOrientationTag() { return getOrientationTag(activity.getResources().getConfiguration().orientation); }
    private String describeOrientation(final int orientation) {
        switch (orientation) {
            case Configuration.ORIENTATION_UNDEFINED: return "ORIENTATION_UNDEFINED";   // 0
            case Configuration.ORIENTATION_PORTRAIT: return "ORIENTATION_PORTRAIT";     // 1
            case Configuration.ORIENTATION_LANDSCAPE: return "ORIENTATION_LANDSCAPE";   // 2
            case Configuration.ORIENTATION_SQUARE: return "ORIENTATION_SQUARE";         // 3
            default: return null;
        }
    }
    @SuppressLint("DefaultLocale")
    private String getOrientationTag(final int orientation) {
        return String.format("[%d:%s]", orientation, describeOrientation(orientation).substring(12, 16).toLowerCase());
    }
}

活动.java

package xxx.android.app;

import xxx.android.ActivityCore;
import xxx.android.ActivityCore.ActivityCallbackInterface;
import android.os.Bundle;

public abstract class Activity extends android.app.Activity implements ActivityCallbackInterface {
    private final ActivityCore activityCore;

    public Activity() { super(); activityCore = new ActivityCore(this); }

    @Override
    protected void onCreate(Bundle savedInstanceState) { activityCore.onCreate(savedInstanceState); }
    @Override public void onCreateCallback(Bundle savedInstanceState) { super.onCreate(savedInstanceState); }

    @Override
    public void onBeforeSaveInstanceState(Bundle outState) {}       // Optionally: let child class override
    @Override
    protected void onSaveInstanceState(Bundle outState) { activityCore.onSaveInstanceState(outState); }
    @Override public void onSaveInstanceStateCallback(Bundle outState) { super.onSaveInstanceState(outState); }

    public final int getCurrentOrientation() { return activityCore.getCurrentOrientation(); }

    public final boolean isDevicePortrait() { return activityCore.isDevicePortrait(); }
    public final boolean isDeviceLandscape() { return activityCore.isDeviceLandscape(); }
    public final boolean isNewDevicePortrait() { return activityCore.isNewDevicePortrait(); }
    public final boolean isNewDeviceLandscape() { return activityCore.isNewDeviceLandscape(); }
    public final boolean isPortrait2Landscape() { return activityCore.isPortrait2Landscape(); }
    public final boolean isLandscape2Portrait() { return activityCore.isLandscape2Portrait(); }

    public final String describeCurrentOrientation() { return activityCore.describeCurrentOrientation(); }
    public final String getCurrentOrientationTag() { return activityCore.getCurrentOrientationTag(); }
    public final String describeNewOrientation() { return activityCore.describeNewOrientation(); }
    public final String getNewOrientationTag() { return activityCore.getNewOrientationTag(); }
}

片段活动.java

package xxx.android.support.v4.app;

import xxx.android.ActivityCore;
import xxx.android.ActivityCore.ActivityCallbackInterface;
import android.os.Bundle;

public abstract class FragmentActivity extends android.support.v4.app.FragmentActivity implements ActivityCallbackInterface {
    private final ActivityCore activityCore;

    public FragmentActivity() { super(); activityCore = new ActivityCore(this); }

    @Override
    protected void onCreate(Bundle savedInstanceState) { activityCore.onCreate(savedInstanceState); }
    @Override public void onCreateCallback(Bundle savedInstanceState) { super.onCreate(savedInstanceState); }

    @Override
    public void onBeforeSaveInstanceState(Bundle outState) {}       // Optionally: let child class override
    @Override
    protected void onSaveInstanceState(Bundle outState) { activityCore.onSaveInstanceState(outState); }
    @Override public void onSaveInstanceStateCallback(Bundle outState) { super.onSaveInstanceState(outState); }

    public final int getCurrentOrientation() { return activityCore.getCurrentOrientation(); }

    public final boolean isDevicePortrait() { return activityCore.isDevicePortrait(); }
    public final boolean isDeviceLandscape() { return activityCore.isDeviceLandscape(); }
    public final boolean isNewDevicePortrait() { return activityCore.isNewDevicePortrait(); }
    public final boolean isNewDeviceLandscape() { return activityCore.isNewDeviceLandscape(); }
    public final boolean isPortrait2Landscape() { return activityCore.isPortrait2Landscape(); }
    public final boolean isLandscape2Portrait() { return activityCore.isLandscape2Portrait(); }

    public final String describeCurrentOrientation() { return activityCore.describeCurrentOrientation(); }
    public final String getCurrentOrientationTag() { return activityCore.getCurrentOrientationTag(); }
    public final String describeNewOrientation() { return activityCore.describeNewOrientation(); }
    public final String getNewOrientationTag() { return activityCore.getNewOrientationTag(); }
}

最后,我真的要感谢你们如此乐于助人,并不断与我一起更新解决进度!你们都是使 stackoverflow 成为程序员的完美网站的关键人物。如果您在我的代码中发现任何问题,或者有任何改进空间,请不要犹豫再次帮助我 :-)

一些改进?

因为onBeforeSaveInstanceState()是在使用时实现的,所以这三个类都需要保留abstract。这会导致成员变量的重复current_orientation。如果current_orientation可以放入class ActivityBase,或将其分组到其他地方,那就更好了!

愚蠢的我。我已经修好了:-)

4

4 回答 4

1

在我看来,这里最好的解决方案是将逻辑委托给某个类,我们称之为CustomActivityLogic.

CustomActivity如果您想从逻辑类访问活动类的某些数据或方法,您还需要为活动创建通用接口 ( )。

要调用受保护的虚拟覆盖方法,有两种解决方案:

  • 从重写的方法调用晚餐的方法
  • 在子类中创建一个新方法并从这个新方法调用超级方法。从共享逻辑调用新方法。

CustomActivity.java

public interface CustomActivity {
    void someMethod();
}

Activiti.java

import android.app.Activity

public class Activiti 
    extends Activity 
    implements CustomActivity {

    private CustomActivityLogic logic = new CustomActivityLogic();

    public void someMethod() { /***/ }

    public void myNewMethod() { logic.myNewMethod(this); }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        logic.onCreate(this, savedInstanceState); // call shared logic
        super.onCreate(savedInstanceState); // call super
    }
}

FragmentActivitii.java

import android.support.v4.app.FragmentActivity;

public class FragmentActivitii 
    extends FragmentActivity 
    implements CustomActivity {

    private CustomActivityLogic logic = new CustomActivityLogic();

    public void someMethod() { /***/ }

    public void myNewMethod() { logic.myNewMethod(this); }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        logic.onCreate(this, savedInstanceState); // call shared logic
        super.onCreate(savedInstanceState); // call super
    }
}

CustomActivityLogic.java

 public class CustomActivityLogic {
     public void myNewMethod(CustomActivity activity) { /*...*/ }
     public void onCreate(Activity activity, Bundle savedInstanceState) { 
         /* shared creation logic */
     }
 }

使 onCreate 可通过CustomActivity接口从外部调用的方法

CustomActivity.java

public interface CustomActivity {
    void someMethod();
    void onCreateSuper(Bundle savedInstanceState);
}

Activiti.java

import android.app.Activity

public class Activiti 
    extends Activity 
    implements CustomActivity {

    private CustomActivityLogic logic = new CustomActivityLogic();

    public void someMethod() { /***/ }

    public void myNewMethod() { logic.myNewMethod(this); }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        logic.onCreate(this, savedInstanceState); // call shared logic
    }

    public void onCreateSuper(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); // call super
    }
}

FragmentActivitii.java

import android.support.v4.app.FragmentActivity;

public class FragmentActivitii 
    extends FragmentActivity 
    implements CustomActivity {

    private CustomActivityLogic logic = new CustomActivityLogic();

    public void someMethod() { /***/ }

    public void myNewMethod() { logic.myNewMethod(this); }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        logic.onCreate(this, savedInstanceState); // call shared logic
    }

    public void onCreateSuper(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); // call super
    }
}

CustomActivityLogic.java

 public class CustomActivityLogic {
     public void myNewMethod(CustomActivity activity) { /*...*/ }
     public void onCreate(CustomActivity activity, Bundle savedInstanceState) { 
         /* shared creation logic */
         activity.onCreateSuper(savedInstanceState); // call-back super
     }
 }
于 2013-04-01T23:04:10.823 回答
1

您希望添加帮助跟踪方向的辅助方法。我认为这还不足以保证创建子类。

把它们放在一个辅助类中:

public class OrientationHelper {
    private Activity activity;
    private int current_orientation;

    public OrientationHelper(Activity activity){
        this.activity = activity;
        orientation = Configuration.ORIENTATION_UNDEFINED;
    }

    public int getNewOrientation() { 
        return activity.getResources().getConfiguration().orientation;
    }

    // call this when you wish to update current_orientation
    public void updateOrientation() {
        current_orientation = getNewOrientation();
    }

    public int getCurrentOrientation() { 
        return current_orientation; 
    }

    public boolean isDevicePortrait() { 
        return current_orientation == Configuration.ORIENTATION_PORTRAIT; 
    }

    public boolean isDeviceLandscape() { 
        return current_orientation == Configuration.ORIENTATION_LANDSCAPE; 
    }

    public boolean isNewDevicePortrait() { 
        return getCurrentOrientation() == Configuration.ORIENTATION_PORTRAIT; 
    }

    public boolean isNewDeviceLandscape() { 
        return getCurrentOrientation() == Configuration.ORIENTATION_LANDSCAPE; 
    }

    public boolean isPortrait2Landscape() { 
        return isDevicePortrait() && isNewDeviceLandscape(); 
    }

    public boolean isLandscape2Portrait() { 
        return isDeviceLandscape() && isNewDevicePortrait(); 
    }

    public String describeCurrentOrientation() { 
        return describeOrientation(current_orientation); 
    }

    public String describeNewOrientation() { 
        return describeOrientation(getNewOrientation());
    }

    private String describeOrientation(int current_orientation) {
        switch (current_orientation) {
            case Configuration.ORIENTATION_UNDEFINED: 
                return "ORIENTATION_UNDEFINED";
            case Configuration.ORIENTATION_PORTRAIT: 
                return "ORIENTATION_PORTRAIT";
            case Configuration.ORIENTATION_LANDSCAPE: 
                return "ORIENTATION_LANDSCAPE";
            case Configuration.ORIENTATION_SQUARE: 
                return "ORIENTATION_SQUARE";
            default: return null;
        }
    }
}

在那些使用方向的活动中(并且只有那些),您可以实例化 OrientationHelper 并在选定的位置调用 updateOrientation()。

另一段代码,用于组织实例状态的保存,我不会将其放入不同的类中,以便您可以重用它。因为这不是人们期望对状态保存进行修改的地方,因此它可能会被忽略。(我花了一点时间滚动来弄清楚它应该做什么。)

我认为最易读的方法是在你使用它的每个活动中明确地写出来。

最后要考虑的一件事是 Sherlock Actionbar 已经扩展了 Activity。我认为这是正确的。但这意味着如果你也扩展 Activity,你偶尔会遇到麻烦。

于 2013-04-02T21:38:55.587 回答
0

如何使用Decorator Pattern?不幸的是,这将要求您委托所有现有的方法,或者为您的目的所必需的任何方法。

public class ActivityDecorator extends Activity 
{
    private Activity RealActivity;
    public ActivityDecorator(Activity _realActivity)
    {
        RealActivity = _realActivity;
    }

    public void myNewMethod() { ... }  // this exposes the added/new functionality

    // unfortunately for old functionality you need to delegate
    public void oldMethod() { RealActivity.oldMethod(); }
}

但是,一旦您为ActivityProxy该类完成了一次,您就可以构造ActivityDecorator具有派生类型的实例,Activity例如FragmentActivity在您的情况下。例如

ActivityDecorator decorator = new ActivityDecorator(new FragmentActivity());
于 2013-04-01T23:05:51.237 回答
0

您的设计问题是即将到来的 Java 8 虚拟扩展解决的问题之一。有关更多详细信息,请参见下面的 URL:

http://java.dzone.com/articles/java-8-virtual-extension

与此同时,没有简单的方法。装饰器类将不起作用,而是实现一个实用程序类,您的两个类都将调用它:

根据新信息编辑:

/** NOTE: cannot be abstract class **/
public class ActivitiBase {
   private int current_orientation = Configuration.ORIENTATION_UNDEFINED;  // ORIENTATION_UNDEFINED = 0

    private Activity activity;
    public void ActivitiBase(Activity activity) {
        this.activity = activity;
    }

   public void onCreate(Bundle savedInstanceState) {
      current_orientation = activity.getResources().getConfiguration().orientation;
   }

   public boolean isDevicePortrait() { return current_orientation == 
                      Configuration.ORIENTATION_PORTRAIT; }
   }    

   public void myNewMethod() { ... }
}

活动课:

public class Activiti extends Activity {
    private ActiviBase activitiBase;

    public Activiti() {
       activitiBase = new ActiviBase(this);
    }

    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      activitiBase.onCreate(savedInstanceState);
    }

    public void myNewMethod() { 
       activitiBase.myNewMethod();
    }
}

FrameActiviti 类:

public class FrameActiviti extends FrameActivity {
    private ActiviBase activitiBase;

    public FrameActiviti() {
       activitiBase = new ActiviBase(this);
    }

    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      activitiBase.onCreate(savedInstanceState);
    }

    public void myNewMethod() { 
       activitiBase.myNewMethod();
    }
}
于 2013-04-02T00:57:33.953 回答