2012-10-25 29 views
8

Tôi đã gặp phải sự cố thú vị. Nếu bạn viết đoạn mã sau vào phương pháp onCreate/onStart/onResume hoạt động:Không có lỗi "Chỉ chuỗi ban đầu đã tạo phân cấp chế độ xem mới có thể chạm vào chế độ xem" khi chế độ xem được cập nhật không chậm trễ

final Button myButton = (Button)findViewById(R.id.myButton); 
final TextView myTextView = (TextView)findViewById(R.id.myTextView); 
final Thread thread = new Thread(new Runnable() { 
    @Override 
    public void run() { 
     myTextView.setText("Hello text"); 
    } 
}); 
myButton.setOnClickListener(new OnClickListener() { 
    @Override 
     public void onClick(View v) { 
     thread.start(); 
    } 
}); 

hay:

final TextView myTextView = (TextView)findViewById(R.id.myTextView); 
final Thread thread = new Thread(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      Thread.currentThread().sleep(500); 
     } 
     catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     myTextView.setText("Hello text"); 
    } 
}); 
thread.start(); 

nó như thế nào nên được, một lỗi được ném

android.view.ViewRoot $ CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views." 

Rõ ràng là trong trường hợp này, tôi phải cập nhật chế độ xem trong ui-thread(Handler, AsyncTask, runOnUiThread, view.post).

Nhưng nếu bạn cập nhật chế độ xem trong một chuỗi khác mà không bị chậm trễ (không cần gọi điện hoặc không bắt đầu chuỗi bằng cách nhấn một nút), thì ngoại lệ sẽ không được ném.

final TextView myTextView = (TextView)findViewById(R.id.myTextView); 
final Thread thread = new Thread(new Runnable() { 
    @Override 
    public void run() { 
     myTextView.setText("Hello text"); 
    } 
}); 
thread.start(); 

Ai có thể cho tôi biết tại sao có hành vi như vậy?

UPDATE:

Tôi đã học được mã nguồn của Android và đi đến kết luận sau đây. Nandeesh đã viết sự thật. Khi khởi tạo chế độ xem được gọi là phương thức dispatchAttachedToWindow (AttachInfo info, int visibility) của Chế độ xem, khởi tạo trường mAttachInfo. Đối tượng mAttachInfo có trường mViewRootImpl. Nếu nó là null, getViewRootImpl sẽ trả về là null:

public ViewRootImpl getViewRootImpl() { 
     if (mAttachInfo != null) { 
      return mAttachInfo.mViewRootImpl; 
     } 
     return null; 
    } 

ViewRootImpl chứa phương thức checkThread. Nó so sánh các luồng: luồng tạo ra khung nhìn và luồng của yêu cầu để cập nhật khung nhìn.

void checkThread() { 
     if (mThread != Thread.currentThread()) { 
      throw new CalledFromWrongThreadException(
        "Only the original thread that created a view hierarchy can touch its views."); 
     } 
    } 

Do đó, nếu chế độ xem không được khởi tạo, không có kiểm tra và thay đổi nào không ném ngoại lệ.

+0

Có, tôi cũng đã thử nghiệm với thông số chậm trễ. Nhưng tôi tự hỏi tại sao. Dường như chủ đề mất một chút thời gian để khởi tạo, trong đó chúng tôi có thể thay đổi thành phần ui. Nhưng tôi chưa thấy đề cập đến điều này trong tài liệu. –

+0

Tôi nghĩ rằng "chậm trễ" là do những gì 'nandeesh' nói trong câu trả lời của mình. Đó có lẽ là câu trả lời. – Luksprog

Trả lời

9

Việc kiểm tra chỉ xuất hiện khi hoàn thành quá trình chuyển tiếp textView. Nhưng bố cục của khung nhìn chỉ được thực hiện sau khi gọi OnCreate. Vì vậy, cho đến khi Ui không được hiển thị, việc thay đổi textView sẽ không dẫn đến việc vô hiệu hóa chế độ xem.

Nhưng khi textView đã được hiển thị, yêu cầu chuyển tiếp giao diện người dùng, trong trường hợp đó chuỗi được chọn. Vì vậy, bạn nhận được ngoại lệ chỉ sau một thời gian của Oncreate nhưng không phải ngay lập tức.

+0

Cảm ơn bạn đã trả lời. Rất giống với sự thật. –

Các vấn đề liên quan