2012-10-06 11 views
5

Ho creato il mio primo wallpaper live che implementa il disegno in un thread separato. Così ora ho un WallpaperService e il mio WallpaperPainter che fa il lavoro. Il problema è che ottengo un IllegalArgumentException nel metodo unlockCanvasAndPost su alcuni dispositivi (Samsung Note è quello). Ho letto tutte le raccomandazioni che ho trovato ma non ho potuto correggere quell'errore. Sembra che lo unlockCanvasAndPost venga chiamato quando la superficie viene distrutta, quindi la tela non è valida. Ecco le parti essenziali di codice:IllegalArgumentException in unlockCanvasAndPost (Android live wallpaper)

Nel servizio di carta da parati:

@Override 
    public void onSurfaceChanged(SurfaceHolder holder, int format, int width, 
      int height) { 
     super.onSurfaceChanged(holder, format, width, height); 
     painting.setSurfaceSize(width, height); 
    } 

    @Override 
    public void onSurfaceCreated(SurfaceHolder holder) { 
     super.onSurfaceCreated(holder); 
     painting.start(); 
    } 

    @Override 
    public void onSurfaceDestroyed(SurfaceHolder holder) { 
     boolean retry = true; 
     painting.stopPainting(); 
     while (retry) { 
      try { 
       painting.join(); 
       retry = false; 
      } catch (InterruptedException e) { } 
     } 
     super.onSurfaceDestroyed(holder); 
    } 

Nel thread dipinto:

public void stopPainting() { 
    this.run = false; 
    synchronized(this) { 
     this.notify(); 
    } 
} 

public void run() { 
    this.run = true; 
    Canvas c = null; 
    while (run) { 
     try { 
      synchronized (this) { 
       Thread.sleep(50); 
       c = this.surfaceHolder.lockCanvas(); 
       doDraw(c); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } finally { 
      if (c != null) { 
       this.surfaceHolder.unlockCanvasAndPost(c); // << -- HERE IS THE PROBLEM 
      } 
     } 
     // if pause... 
     synchronized (this) { 
      if (wait) { 
       try { 
        wait(); 
       } catch (Exception e) { } 
      } 
     } 
    } 
} 

Qualcuno mi può dare alcuna idea di cosa sto facendo male? Sono nuovo sia per Java che per Android.

risposta

1

Non vedo un problema definitivo, ma qui ci sono alcuni pensieri.

  • C'è una possibilità che si sblocchi una tela che non è stata bloccata. Impostare c = null; nella parte superiore del ciclo while altrimenti il ​​valore precedente di c verrà sbloccato la volta successiva attraverso il ciclo.

    while (run) { 
        Canvas c = null; 
        ... 
    
  • vostro campo run deve essere contrassegnato come volatile perché vi si accede da più thread.

  • Non chiamare mai Thread.sleep(...) all'interno di un blocco synchronized. Questa è una pessima pratica poiché blocca inutilmente altri thread.

  • Assicurarsi di registrare almeno le eccezioni. Fai molta attenzione a catch (Exception e) {}. Tutto ciò che fa è mascherare i tuoi problemi.

  • Non c'è molto senso nel fare il join() all'interno di un ciclo while. Se il tuo thread viene interrotto, devi interrompere il thread di pittura e uscire.

  • Dal momento che si sia dormendo e attesa, avrebbe più senso per rimuovere il sonno e fare qualcosa di simile:

    try { 
        synchronized (this) { 
         if (wait) { 
          wait(); 
         else { 
          wait(50); 
         } 
        } 
    } catch (Exception e) { 
        e.printStackTrace(); 
    } 
    
2

Se l'errore è: UnlockAndPost riuscita, significa non ha sbloccato nessun buffer. Dopo this.surfaceHolder.unlockCanvasAndPost(c);
è possibile aggiungere
this.surfaceHolder.lockCanvas();
(mi dispiace per il mio povero conoscenza della lingua inglese)

2

Quando si apre l'anteprima di carta da parati, crea l'oggetto WallpaperService e inoltre crea un'istanza di motore. Quindi lo stream inizia a disegnare lo sfondo.

Quindi, quando si fa clic su "Imposta sfondo", non viene creata una nuova istanza di WallpaperService. Ma chiama il metodo onCreateEngine(), che restituisce un'altra (seconda) istanza di Engine.Che gestisce anche il proprio thread.

Ora avete due thread in competizione !!! Quindi portano a un'eccezione generata.

Tutto ciò che devi fare per correggere il bug - è scrivere un metodo corretto suCreateEngine().

sostituire questo:

@Override 
public Engine onCreateEngine() { 
    return new SampleEngine(); 
} 

a questo:

private SampleEngine engine; 

@Override 
public Engine onCreateEngine() { 

    if (engine!=null) { 
     engine.painting.stopPainting(); 
     engine = null; 
    } 
    engine = new SampleEngine(); 
    return engine; 
} 
1

Ho avuto lo stesso problema con la mia carta da parati dal vivo. Su un emulatore Nexus 5 funziona bene, ma quando lo eseguo su un emulatore Nexus 10 si blocca nel momento in cui l'app viene caricata.

Ho scoperto che il problema era perché la skin di default per l'emulatore ha la risoluzione sbagliata. Dopo aver cambiato Skin in "No Skin", non ho più avuto il crash.

Per ulteriori informazioni su come risolvere la pelle con risoluzione sbagliata, si prega di consultare: Android Studio - Tablet emulator not showing correct resolution

Problemi correlati