Skocz do zawartości
p107

Modyfikacja interfejsu z wątku potomnego

    Rekomendowane odpowiedzi

    p107

    Cześć,

    Mam pytanie związane z przykładowym programem. Program łączy się z serwerem, wysyła informacje o naciśniętych klawiszach i odbiera wiadomości od serwera - komunikacja działa poprawnie. W momencie próby wyświetlenie wiadomości otrzymanej od serwera występuje wyjątek dla wywołania metody 'dopisz', co ciekawe ta sama metoda wywołana kilka linijek wyżej działa poprawnie.

    Generalnie rozumiem z czego wynika wyjątek i wiem jak rozwiązać to inaczej - chciałbym jednak zrozumieć dlaczego w tym przykładzie "a.dopisz("\nStart klienta...\n");" wykonuje się poprawnie a wywołanie tej samej metody kilka linijek niżej (w pętli? czy to przez to, że w pętli?) działa poprawnie.

     android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
        at android.view.ViewRoot.checkThread(ViewRoot.java:2683)
        at android.view.ViewRoot.invalidateChild(ViewRoot.java:570)
        at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:596)
        at android.view.ViewGroup.invalidateChild(ViewGroup.java:2396)
        at android.view.View.invalidate(View.java:4945)
        at android.widget.TextView.updateAfterEdit(TextView.java:4736)
        at android.widget.TextView.handleTextChanged(TextView.java:6158)
        at android.widget.TextView$ChangeWatcher.onTextChanged(TextView.java:6316)
        at android.text.SpannableStringBuilder.sendTextChange(SpannableStringBuilder.java:889)
        at android.text.SpannableStringBuilder.change(SpannableStringBuilder.java:352)
        at android.text.SpannableStringBuilder.change(SpannableStringBuilder.java:269)
        at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:432)
        at android.text.SpannableStringBuilder.append(SpannableStringBuilder.java:259)
        at android.text.SpannableStringBuilder.append(SpannableStringBuilder.java:28)
        at android.widget.TextView.append(TextView.java:2236)
        at android.widget.TextView.append(TextView.java:2223)
        at org.przyklad.androsocket.AndroSocketActivity.dopisz(AndroSocketActivity.java:42)
        at org.przyklad.androsocket.AndroSocketActivity$Czytacz.run(AndroSocketActivity.java:82)
    

    public class AndroSocketActivity extends Activity {
    
       @Override
       public void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.main);
           try {
    		ss = new Socket("192.168.0.127",4444);
    		out = new PrintWriter(ss.getOutputStream(), true);
    	} catch (UnknownHostException e) {
    		e.printStackTrace();
    	} catch (IOException e) {
    		e.printStackTrace();
    	}
    
           this.tv = (TextView) findViewById(R.id.hello_text);
           Czytacz czytacz = new Czytacz(this.ss, this);
       }
    
       public void dopisz(String s) {
    	this.tv.append(s);
    }
    
       private TextView tv;
       private Socket ss;
       private PrintWriter out;
    
       public boolean onKeyDown(int keyCode, KeyEvent event) {
       	out.println("Android onKeyDown; code="+keyCode);
       	return false;
       }
    
       class Czytacz extends Thread {
    
       	Czytacz(Socket ss, AndroSocketActivity a) {
       		this.ss = ss;
       		this.a = a;
       		this.start();
       	}
    
       	private Socket ss;
       	private AndroSocketActivity a;
       	private BufferedReader in;
    
       	public void run() {
    
       		try {
       			        a.dopisz("\nStart klienta...\n"); // [b]<================= TUTAJ DZIAŁA[/b]
    			in = new BufferedReader(new InputStreamReader(this.ss.getInputStream()));
    			String s = new String();
    			while ((s = in.readLine()) != null) {
    				Log.d("W_PETLI",s);
    				a.dopisz(s); // [b]<=================== TUTAJ WYSTĘPUJE WYJĄTEK[/b]
        		}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    
       	}
       }
    
    
    }

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    piotrpo

    Bo pętla chodzi ci w innym wątku, który przecież jasno deklarujesz...

    Musisz utworzyć w wątku głównym obiekt Handler a z wątku pobocznego nie wywoływać metody zdefiniowanej bezpośrednio na activity, tylko wysyłać wiadomość do Handler, żeby ją to on ją wywołał.

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    napisz sobie klasę upraszczającą całą procedurę przykładowo taką:

    public abstract class Interface<Relay> {
    
    private final InternalHandler mHandler = new InternalHandler();
    
    public void sendForground(int what, Relay relay) {
    	Message message = mHandler.obtainMessage(what, relay);
    	message.sendToTarget();
    }
    
    private class InternalHandler extends Handler {
    
    	@Override
    	@SuppressWarnings("unchecked")
    	public void handleMessage(Message message) {
    		forground(message.what, (Relay) message.obj);
    	}
    
    }
    
    protected abstract void forground(int what, Relay relay);
    
    }

    teraz jak chcesz coś wykonać z watka co wpływa na elementy w wątku UI wystarczy ze zrobisz klasę rozszerzającą potem tworzysz obiekt i używasz

    private final InternalInterface mInternalInterface = new InternalInterface();
    
    private class InternalInterface extends Interface<String> {
    
    @Override
    protected void forground(int what, String string) {
    	//to się wykona w wątku UI
    }
    
    } 
    
    mInternalInterface.sendForground(1, "coś");//to wykonujesz w wątku nie UI

    można zdefiniować dowolny rodzaj danych do przekazania lub Void jak nic nie chcemy przekazać a jedynie wykonać

    pewnie zaraz ktoś to napisze więc dodam ja, można tez użyć runOnUiThread() albo zamiast Thread AsyncTask

    Edytowane przez zawadaki

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

    Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

    Zarejestruj nowe konto

    Załóż nowe konto. To bardzo proste!

    Zarejestruj się

    Zaloguj się

    Posiadasz już konto? Zaloguj się poniżej.

    Zaloguj się

    • Ostatnio przeglądający   0 użytkowników

      Brak zarejestrowanych użytkowników przeglądających tę stronę.

    x