2015-05-24 10 views
9

Ho classe che si estende da un View e sto cercando di mostrare un popupWindow utilizzando questo codicechiamando showAtLocation di PopupWindow si blocca l'applicazione

public class dbView extends View implements View.OnTouchListener { 

    private void showDialog(String msg) { 
     LayoutInflater layoutInflater; 
     View dialogContent; 
     final PopupWindow popupWindow; 

     layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     dialogContent = layoutInflater.inflate(R.layout.pop_up_dialog, null); 

     popupWindow = new PopupWindow(
       dialogContent, 
       ViewGroup.LayoutParams.WRAP_CONTENT, 
       ViewGroup.LayoutParams.WRAP_CONTENT); 

     popupWindow.showAtLocation(this, Gravity.CENTER, 10, 10); 

    } 

} 

La mia applicazione si blocca quando si tenta di eseguire tale ultima riga. Il messaggio di eccezione è

Impossibile creare il gestore di filettatura interna che non ha chiamato Looper.prepare()

Ho cercato risposte relative a quel messaggio e tutti loro coinvolgimento che il popup è stato creato su un thread separato e che dovrei usare runOnUIThread ma se mi trovo all'interno di VIEW ho bisogno di questo? Quale può essere la causa di questo problema?

+0

lei ha detto, avendo un errore come "Impossibile creare gestore filettatura interna che non ha chiamato Looper.prepare()", ma dove si parla di codice circa l'uso di "Handler". per favore mi spieghi correttamente con il tuo codice fatto in modo da poter provare per te. –

risposta

3

Dipende da dove stai chiamando showDialog(String msg), so che lo stavi chiamando dalla tua classe View, ma questo non significa che sia sul thread dell'interfaccia utente, le chiamate View vengono elaborate sul thread dell'interfaccia utente, ma se fai una chiamata View in una discussione avrai questo errore. so che lo stesso codice è stato risolto da solo, ma se esegui TimerTask o Thread nella tua classe View dovresti ricontrollarli. E anche al posto di runOnUithread puoi chiamare lo post(runnable); (lo stesso meccanismo Handler) nella tua classe View, che farà in modo che la chiamata eseguibile venga inviata al thread principale.

sotto controllo breve in cui si chiama nel vostro View classe

+0

Cosa succede se un TimerTask chiama un metodo dalla vista che mostra la finestra di dialogo, devo usare RunUiThread su quella chiamata? –

+0

sì, come un 'TimerTask' esegue Thread diversi- (crea un nuovo thread), quindi anche se stai chiamando i tuoi metodi in una View che dovrebbero essere sul thread dell'interfaccia utente, non è ... do mi prendi signore? se vuoi passare al thread UI nella tua classe View usa il metodo post, è lo stesso di quello, 'Handler' è nella mia risposta @ MauricioGracia – Elltz

1

Suppongo che potrebbe essere causato dal fatto che stai cercando di interferire con la tua interfaccia utente da un thread non originale (che ha creato l'interfaccia utente). La tua classe di visualizzazione personalizzata non ha accesso alla modifica dell'interfaccia utente, quindi penso che il modo migliore per farlo sia chiamare runOnUIThread(). Anche se ho sentito che usare runOnUIThread potrebbe non essere la scelta migliore ma mi sembra che questo sarà esattamente quello che ti serve nel tuo caso.

Di solito per ottenere questo lavoro ho fare una classe speciale che si estende Application (nel mio caso è ContextGetter) e implementare un metodo come questo:

public class ContextGetter extends Application { 

    private static Context context; 

    public void onCreate(){ 
     super.onCreate(); 
     context = getApplicationContext(); 
    } 

    public static Context getAppContext() { 
     return context; 
    } 
} 

Mi aiuta a ottenere il contesto applicazione da ogni dove. Dovresti anche aggiungerlo al tuo manifest in questo modo:

<application 
     android:name=".ContextGetter" 
     android:allowBackup="true" 
     android:icon="@drawable/ic_launcher" 
     android:label="@string/app_name" 
     android:theme="@style/AppTheme" > 

e includere tutte le attività in questo tag.

Quando hai il tuo contesto si può fare questa cosa:

((Activity)ContextGetter.getAppContext()).runOnUiThread(new Runnable() 
{ 
//doSomethingInside 
}); 

Può sembrare strano, ma deve lavorare per voi. Sembra in questo modo perché Activity è derivato da Context. Ogni volta che ci provi mi piacerebbe sapere se ha funzionato. Spero di aver contribuito con la domanda

+0

Lo chiamo dalla stessa vista !! –

+0

potresti fornirmi un esempio specifico –

+0

Crederci o meno, era solo questione di offrire la taglia e ora usare lo stesso codice di quello che ho postato ora funziona !! –

1

in palese

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> 

si può fisso che facendo proprio attraverso il window manager.

private void showCustomPopupMenu() 
{ 
      windowManager2 = (WindowManager)getSystemService(WINDOW_SERVICE); 
      LayoutInflater layoutInflater=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      View view=layoutInflater.inflate(R.layout.xxact_copy_popupmenu, null); 
      params=new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT, 
        WindowManager.LayoutParams.WRAP_CONTENT, 
        WindowManager.LayoutParams.TYPE_PHONE, 
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, 
        PixelFormat.TRANSLUCENT); 

      params.gravity=Gravity.CENTER|Gravity.CENTER; 
      params.x=10; 
      params.y=10; 
      windowManager2.addView(view, params); 
}