2012-07-21 24 views
6

En mi programa de Android una Actividad llama a una nueva clase de vista de superficie, que a su vez llama a una nueva clase de subproceso. Quiero poder pasar un valor a la clase de subproceso de los métodos onPause y onResume de la actividad, para poder pausar y reanudar el subproceso. La única manera que conozco de pasar estos datos es creando una nueva instancia, que simplemente crearía un hilo diferente. ¿Cómo debo hacer esto sin crear una nueva instancia de subprocesos?Pasar un valor de la actividad al hilo después de que el hilo ya está creado

public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(new GameSurface(this)); 
} 

@Override 
protected void onResume() { 
    super.onResume(); 
      //Would like to pass this value 
      int state = 1; 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
      //Would like to pass this value 
      int state = 2; 
} 
+0

He actualizado mi respuesta con 2 clases y una implementación en funcionamiento del 'AtomicInteger'. Saludos – Killrawr

Respuesta

4

Un poco de historia sobre la concurrencia

Pasar valores en concurrencia es la parte fácil. Mire en el tipo de datos AtomicInteger (Más información here). Atomicity también significa All or nothing. Este tipo de datos no necesariamente está enviando datos entre subprocesos o procesadores (como lo haría con mpi), sino que simplemente está compartiendo datos en su memoria compartida.

Pero lo que es una acción atómica? ....

una operación atómica es una operación que se lleva a cabo como una sola unidad de trabajo sin posibilidad de interferencia de otras operaciones.

En Java, la especificación del lenguaje garantiza que leer o escribir una variable es atómico (a menos que la variable sea de tipo largo o doble). De largo y dobles sólo atómica si se declaran como volátil ....

crédito (Java Concurrency/Multithreading - Tutorial por Lars Vogel)

le recomiendo que lea esto, que cubre todo, desde atomicity, thread pools, deadlocks y the "volatile" and "synchronized" keyword.


Iniciar claseEsto ejecutará un nuevo hilo (También puede ser referido como nuestra Main Thread).

import java.util.concurrent.atomic.AtomicInteger; 
/** 
* @author Michael Jones 
* @description Main Thread 
*/ 
public class start { 
    private AtomicInteger state; 
    private Thread p; 
    private Thread r; 
    /** 
    * constructor 
    * initialize the declared threads 
    */ 
    public start(){ 
     //initialize the state 
     this.state = new AtomicInteger(0); 
     //initialize the threads r and p 
     this.r = new Thread(new action("resume", state)); 
     this.p = new Thread(new action("pause", state)); 
    } //close constructor 

    /** 
    * Start the threads 
    * @throws InterruptedException 
    */ 
    public void startThreads() throws InterruptedException{ 
     if(!this.r.isAlive()){ 
      r.start(); //start r 
     } 
     if(!this.p.isAlive()){ 
      Thread.sleep(1000); //wait a little (wait for r to update)... 
      p.start(); //start p 
     } 
    } //close startThreads 

    /** 
    * This method starts the main thread 
    * @param args 
    */ 
    public static void main(String[] args) { 
     //call the constructor of this class 
     start s = new start(); 
     //try the code 
     try { 
      s.startThreads(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } //start the threads 
    } //close main 

} //close class start 

Debido a que el número entero es atómico, también se puede recuperar en cualquier lugar, pero el main method en el Iniciar clase con System.out.println("[run start] current state is... "+state.intValue());. (Si desea recuperarlo de la main method, tendrá que configurar un Setter/Getter, como lo he hecho en el Acción Clase)

Acción ClaseEste es nuestro hilo en la acción (También se lo puede llamar nuestro Slave Thread).

import java.lang.Thread.State; 
import java.util.concurrent.atomic.AtomicInteger; 

/** 
* @author Michael Jones 
* @description Slave Thread 
*/ 
public class action implements Runnable { 

    private String event = ""; 
    private AtomicInteger state; 

    /** 
    * The constructor (this represents the current instance of a thread). 
    * 
    * @param event 
    * @param state 
    */ 
    public action(String event, AtomicInteger state) { 
     this.event = event; // update this instance of event 
     this.state = state; // update this instance of state 
    } // constructor 

    /** 
    * This method will be called after YourThreadName.Start(); 
    */ 
    @Override 
    public void run() { 
     if (this.event == "resume") { 
      this.OnResume(); // call resume 
     } else { 
      this.OnPause(); // call pause 
     } 
    } // close Runnable run() method 

    /** 
    * The resume function Use the auto lock from synchronized 
    */ 
    public synchronized void OnResume() { 
     System.out.println("[OnResume] The state was.." + this.getAtomicState() 
       + " // Thread: " + Thread.currentThread().getId()); 
     this.setAtomicState(2); // change the state 
     System.out.println("[OnResume] The state is.." + this.getAtomicState() 
       + " // Thread: " + Thread.currentThread().getId()); 
    } // close function 

    /** 
    * The pause function Use the auto lock from synchronized 
    */ 
    public synchronized void OnPause() { 
     System.out.println("[OnPause] The state was.." + this.getAtomicState() 
       + " // Thread: " + Thread.currentThread().getId()); 
     this.setAtomicState(1); // change the state 
     System.out.println("[OnPause] The state is.." + this.getAtomicState() 
       + " // Thread: " + Thread.currentThread().getId()); 
    } // close function 

    /** 
    * Get the atomic integer from memory 
    * 
    * @return Integer 
    */ 
    private Integer getAtomicState() { 
     return state.intValue(); 
    }// close function 

    /** 
    * Update or Create a new atomic integer 
    * 
    * @param value 
    */ 
    private void setAtomicState(Integer value) { 
     if (this.state == null) { 
      state = new AtomicInteger(value); 
     } else 
      state.set(value); 
    } // close function 

} // close the class 

de salida La consola

[OnResume] The state was..0 // Thread: 9 
[OnResume] The state is..2 // Thread: 9 
[OnPause] The state was..2 // Thread: 10 
[OnPause] The state is..1 // Thread: 10 

Como se puede ver, el AtomicInteger state está siendo compartida en la memoria entre nuestros hilos r y p.


solución y cosas que buscan ...

Lo único que hay que tener cuidado al hacer la concurrencia es Race Conditions/Deadlocks/Livelocks. Algunos RaceConditions se producen porque Threads se crean en orden aleatorio (y la mayoría de los programadores piensan en el conjunto mental de orden secuencial).

que tienen la línea Thread.sleep(1000); para que mi Main Thread da el flujo esclavo r un poco de tiempo para actualizar el state (antes de permitir p para correr), debido a la orden aleatorio de hilos.

1) Mantenga una referencia al hilo y pase el valor con un método. crédito (SJuan76, 2012)

En la solución que he publicado yo hago mi Main Thread (también conocido como class start) como mi comunicador principal para realizar un seguimiento de la Atomic Integer para mis esclavos a utilizar (también conocido como class action). Mi hilo principal también es updatingmemory buffer para Atomic Integer en mis esclavos (La actualización en el búfer de memoria ocurre en el fondo de la aplicación y es manejada por la clase AtomicInteger).

+0

Gracias. Entonces, ¿tengo que usar un constructor o método AtomicInteger en la clase de subprocesos para obtener el estado actualizado? Lo siento si eso no está bien. Java es bastante nuevo para mí. – zkello

+0

Tienes que usar la declaración AtomicInteger en cada clase (digamos Tengo una clase 'foo' que crea un hilo con la clase' boo') Necesitaría mi 'AtomicInteger x' declarada en ambas clases para poder compartirla a través de la memoria. – Killrawr

+0

También agregue 'synchronized' a su' onPause() 'y' onResume() ', por ejemplo' protected synchronized void onResume() '. Esto permite el bloqueo automático de la rosca o la variable 'state'. Y evitará una posible 'Condición de carrera'. Saludos – Killrawr

3

1) Mantenga una referencia a la secuencia y pase el valor con un método.

2) Durante la creación del hilo, páselo por un objeto compartido con la Actividad. Coloque los valores para pasar al objeto, haga que el hilo lo revise regularmente hasta que se encuentren los valores.

+0

¿La primera solución no causaría posibles condiciones de carrera? si o bien 'onResume' o' onPause' dependen el uno del otro? – Killrawr

1

Utilizo la clase de referencia que yo le puse nombre Share Class. Tiene la variable con tipo volatile.

volátil se utiliza para indicar que el valor de una variable será modificado por diferentes hilos.

public class Share { 
    public static volatile type M_shared; 
} 

para cambiar esta variable, se debe bloquearlo y después de cambiar el valor, liberar el bloqueo. Puede leer y escribir usando Share.M_shared.

Cuestiones relacionadas