2

我在我的 Android Java 项目中调用了两次方法,但我只想调用一次。当我第二次调用该方法时,我想检查该方法是否已经被调用。代码是这样的:

class SomeClass {
    //called with certain condition
    private void a(){
         c(); //first call
    }

    private void b() {
         c(); //second call,check here whether function is invoked already or not,if invoked not invoke here or vice-versa
    }

    //called with certain condition
    private void c() {

    }
}
4

6 回答 6

5

您必须使用布尔值(或计数器)来记录该方法是否已被调用。但是你如何做到这一点取决于你想要计算/限制什么

以下假设您使用计数器:

  • 如果要计算所有上下文中对该方法的所有调用:

     private static int nos_calls;
    
     public void function c() {
         nos_calls += 1;
         // do the call
     }
    
  • 如果您只想计算给定对象的方法调用次数,则:

     private int nos_calls;
    
     public void function c() {
         nos_calls += 1;
         // do the call
     }
    
  • 如果您想防止该方法被多次调用:

     private int nos_calls;
    
     public void function c() {
         if (nos_calls++ == 0) {
             // do the call
         }
     }
    
  • 如果可以从不同的线程调用该方法,那么您需要以正确同步的方式进行计数;例如

     private AtomicInteger nos_calls = new AtomicInteger();
    
     public void function c() {
         if (nos_calls.incrementAndGet() == 1) {
             // do the call
         }
     }
    
  • 等等。

于 2013-04-28T09:23:21.337 回答
2

如果您只想在程序的整个运行时运行一次,请使用类静态变量。如果要每个对象运行一次,请添加对象成员变量

class RunOnce {
     private static boolean methodAHasRunOnce = false;
     private boolean methodBHasRun = false;

     public void methodA() {
         if(RunOnce.methodAHasRunOnce) { return; }
         System.out.println("Hello from methodA!");
         RunOnce.methodAHasRunOnce = true;
     }

     public void methodB() {
        if(this.methodBHasRun) { return; }
         System.out.println("Hello from methodB!");
         this.methodBHasRun = true;
     }
}

现在运行:

RunOnce one = new RunOnce();
RunOnce two = new RunOnce();
one.methodA();  // Output: Hello from methodA!
one.methodB();  // Output: Hello from methodB!

one.methodA();  // No output
one.methodB();  // No output

two.methodA();  // No output
two.methodB();  // Output: Hello from methodB!

two.methodA();  // No output
two.methodB();  // No output
于 2013-04-28T09:25:06.070 回答
1

你可以这样做:

class A{
    static boolean calledBefore = false;
    public void a(){
    ....
         c();
    }
    public void b(){
    ....
         c();
    }
    public void c(){

         if(!calledBefore){
             //This will be executed if c() is not called before
             //Do magic here

             calledBefore = true;
         }
    }
}

calledBeforec()如果您想拥有 A 类的多个实例并且每个实例都允许调用一次,则应该是非静态的。

于 2013-04-28T09:20:47.067 回答
1

我在这里看到2个解决方案:

  1. 通过条件检查执行此操作

public Clazz {
    //private static boolean check = false; // if you want your method to be run once per class
    private boolean check = false; // if you want your method to be run once per class instance

    public void c() {
        if(check) {
            return;
        }
        check = true;
        ....
    }

  1. 通过拦截方法调用(例如 Java 动态代理、javassist、asm 等)或使用 AOP 来做到这一点

但是你必须有一个接口:

public class TestInvocationHandler implements InvocationHandler {

    //private static boolean check = false;
    private boolean check = false;

    private Object yourObject;

    public TestInvocationHandler(Object object) {
        yourObject = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) 
        throws Throwable {
        if(check) {
            return null; // or whatever you need
        }
        check = true;
        return method.invoke(yourObject, args);
    }
}

然后你会像这样创建你的对象:

ObjectInterface i = (ObjectInterface) Proxy.newProxyInstance(ObjectInterface.class.getClassLoader(),
                       new Class<?>[] {ObjectInterface .class},
                       new TestInvocationHandler(new MyImplementingClass()));
于 2013-04-28T09:32:05.970 回答
0

您可以向包含在函数中修改的函数的类添加一个静态字段(例如,只是对其进行修改)以跟踪调用。

于 2013-04-28T09:22:57.847 回答
0

方面将是这个问题的一般解决方案。我绝对不是专家(而且这个例子还没有经过测试),但它会是这样的:

@Aspect
public class CallOnlyOnceAspect {

  @Pointcut("call(* methodThatShouldBeInvokedOnlyOnce(..))")
  void methodThatShouldBeInvokedOnlyOnce() {}

  @Around("methodThatShouldBeInvokedOnlyOnce()")
  public Object preventMultipleCalls(ProceedingJoinPoint thisJoinPoint) {
    // You need to implement this method for your particular methods/counters
    if (hasAlreadyExecuted(thisJoinPoint)) {
      return null;
      // or equivalent return value,
      // e.g. you may have cached the previous return value
    }
    Object result = thisJoinPoint.proceed();
    // Maybe cache result against thisJoinPoint
    return result;
  }

}

在这些地方可以找到更多详细信息:

于 2013-04-28T09:29:23.987 回答