2014-04-22 13 views
5

Tôi đã thực hiện một Fragment, có chứa WebView và tôi muốn xác định một onKeyDown() để trở về từ một trang web sang trang trước đó. Tôi đã làm điều đó, nhưng phần kỳ quặc nhất đối với tôi là chia sẻ biến số WebView từ lớp Fragment của tôi thành lớp Activity vì tôi không thể xác định onKeyDown() trong số Fragment. Vì vậy, tôi chỉ định nghĩa một phương thức get và làm cho nó tĩnh. Nhưng tôi tự hỏi nếu đó là một sai lầm thực sự và ứng dụng của tôi có thể sụp đổ nghiêm trọng trong một số trường hợp.OnKeyDown bên trong đoạn WebView

Fragment Mã của tôi:

public class BrowserFragment extends Fragment { 
    private static WebView webView; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
    } 

    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState){ 
     View v = inflater.inflate(R.layout.fragment_activity, parent, false); 

     getActivity().setTitle(R.string.title_rus); 

     webView = (WebView) v.findViewById(R.id.webView); 
     webView.setWebViewClient(new SwingBrowserClient()); 
     WebSettings webSettings = webView.getSettings(); 
     webSettings.setJavaScriptEnabled(true); 
     Uri data = Uri.parse("http://www.swinginmoscow.ru/m/"); 
     webView.loadUrl(data.toString()); 

     return v; 
    } 

    public static WebView getWebView() { 
     return webView; 
    } 
} 

Activity mã của tôi:

public class MainBrowserActivity extends SingleFragmentActivity { 

    @Override 
    protected Fragment createFragment() { 
     return new BrowserFragment(); 
    } 

    @Override 
    public boolean onKeyDown(int keyCode, KeyEvent event) { 
     if ((keyCode == KeyEvent.KEYCODE_BACK) && BrowserFragment.getWebView().canGoBack()) { 
      BrowserFragment.getWebView().goBack(); 
      return true; 
     } 
     return super.onKeyDown(keyCode, event); 
    } 
} 

Trả lời

8

Nó có thể làm việc, nhưng nó không phải là một ý tưởng tốt. Nó rất có thể gây ra sự cố nếu bạn không xử lý chính xác Fragment hoặc ở đâu đó trong mã của bạn một chút bất cẩn liên quan đến vòng đời của nó. Nhưng có một cách dễ dàng xung quanh điều này. Thay vì sử dụng một phương thức tĩnh, lưu các cá thể và các phương thức gọi trên chính cá thể đó. Bằng cách này bạn có thể kiểm tra nếu trường hợp là null và nếu không phải là Fragment có thể xử lý các cuộc gọi đến goBack() hoặc canGoBack() bản thân:

public class MainBrowserActivity extends SingleFragmentActivity { 

    BrowserFragment browserFragment = null; 

    @Override 
    protected Fragment createFragment() { 
     this.browserFragment = BrowserFragment.newInstance(); 
     return this.browserFragment; 
    } 

    @Override 
    public boolean onKeyDown(int keyCode, KeyEvent event) { 
     if (keyCode == KeyEvent.KEYCODE_BACK && this.browserFragment != null && this.browserFragment.canGoBack()) { 
      this.browserFragment.goBack(); 
      return true; 
     } 
     return super.onKeyDown(keyCode, event); 
    } 
} 

Như bạn có thể thấy các trường hợp BrowserFragment được lưu và sau đó các phương pháp như goBack() hoặc canGoBack() đang kêu gọi bản thân số BrowserFragment. Tất nhiên, bạn phải thực hiện các phương pháp này trong BrowserFragment nhưng đó không phải là một vấn đề:

public class BrowserFragment extends Fragment { 

    public static BrowserFragment newInstance() { 
     BrowserFragment fragment = new BrowserFragment(); 
     return fragment; 
    } 

    private WebView webView; 

    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState){ 
     View v = inflater.inflate(R.layout.fragment_activity, parent, false); 

     getActivity().setTitle(R.string.title_rus); 

     webView = (WebView) v.findViewById(R.id.webView); 
     webView.setWebViewClient(new SwingBrowserClient()); 
     WebSettings webSettings = webView.getSettings(); 
     webSettings.setJavaScriptEnabled(true); 
     Uri data = Uri.parse("http://www.swinginmoscow.ru/m/"); 
     webView.loadUrl(data.toString()); 
     return v; 
    } 

    public boolean canGoBack() { 
     return this.webView != null && this.webView.canGoBack(); 
    } 

    public void goBack() { 
     if(this.webView != null) { 
      this.webView.goBack(); 
     } 
    } 
} 

tôi đã thực hiện một vài cải tiến thêm để mã của bạn. Trước hết, tôi đã thêm kiểm tra null để ngăn bất kỳ NullPointerExceptions nào có thể và thứ hai, khuyên bạn nên luôn sử dụng phương pháp nhà máy tĩnh để tạo các phiên bản mới Fragments. Đó là phương pháp tĩnh newInstance() là tôi đã thêm vào số BrowserFragment. Lợi thế của điều đó là bạn có thể thực hiện một phương pháp chăm sóc thiết lập các BrowserFragment cho bạn bất kể bạn sử dụng nó ở đâu. Bạn có thể thêm tham số vào phương thức newInstance() để chuyển một số giá trị cho số BrowserFragment hoặc để thêm một số người nghe yêu cầu, v.v ... nhưng vì bạn không chuyển bất kỳ giá trị nào cho phương thức BrowserFragment, phương thức newInstance() vẫn còn trống. Tuy nhiên, cách tốt nhất là luôn sử dụng các phương pháp nhà máy như vậy ngay cả khi họ chỉ gọi new BrowserFragment().

Thông thường, cách tiếp cận này tốt hơn nhiều. Đặc biệt là từ quan điểm kiến ​​trúc bởi vì bạn không trực tiếp tương tác với WebView trong Activity. Các WebView không có bất cứ điều gì để làm với các Activity, nó là một phần của việc thực hiện các BrowserFragment và như vậy Activity không nên biết rằng thậm chí có một WebView. Cách thực hiện các cuộc gọi đến goBack() hoặc canGoBack() hoặc những gì họ thực hiện chính xác là không quan tâm đến số Activity. Các Activity chỉ cần nói với các BrowserFragment "Tôi muốn quay trở lại" và các BrowserFragment hiện công việc. Điều này ngăn cách các trách nhiệm tốt hơn và làm cho mã dễ đọc hơn, rõ ràng hơn và dễ bảo trì hơn.

EDIT:

Ngoài ra tôi không biết của một SingleFragmentActivity nhưng nói chung bất kỳ Activity thực hiện onBackPressed() phương pháp.Bạn không cần phải ghi đè onKeyDown() để bắt sự kiện quan trọng. Bạn chỉ có thể làm điều gì đó như sau:

@Override 
public void onBackPressed() { 
    if (this.browserFragment != null && this.browserFragment.canGoBack()) { 
     this.browserFragment.goBack(); 
    } else { 
     // The back key event only counts if we execute super.onBackPressed(); 
     super.onBackPressed(); 
    } 
} 

Nếu bạn có bất kỳ câu hỏi nào khác, vui lòng hỏi!

+0

Oh! Cảm ơn bạn rất nhiều vì đã làm việc chăm chỉ và giải thích! Đó là chính xác những gì tôi muốn thực hiện, nhưng không có idead làm thế nào để (đặc biệt là làm thế nào để làm cho Fragment làm công việc một hoạt động). Hoạt động SIngleFragment của tôi chỉ chứa mã tạo phân đoạn, bắt đầu giao dịch và thêm vào vùng chứa. Cảm ơn bạn! Bây giờ tôi sẽ đi và suy ngẫm về toàn bộ triển khai của bạn =) – Mabjik

+0

Nhân tiện, có thể bạn đã biết, tôi đã thêm WebView vào phân đoạn để vòng đời hoạt động sẽ không ảnh hưởng đến việc biểu diễn trang. Ví dụ: tôi đã thay đổi từ chế độ dọc sang chế độ ngang và tôi không muốn ứng dụng của mình tải xuống trang bắt đầu lại. Tôi nên lưu một cái gì đó trong saveInstanceState, nhưng tôi nên lưu cái gì? – Mabjik

+0

Cảm ơn, +1 cho mã rõ ràng và giải thích tốt. Nó hoạt động hoàn hảo cho tôi! Tôi chỉ có một câu hỏi, làm thế nào tôi có thể xử lý khi tôi có một menu trong Android mở ra các liên kết bên trong webview của tôi? Khi tôi nhấp vào liên kết bên trong của webview hoạt động tốt đẹp nhưng khi tôi bấm vào menu "Hồ sơ" và sau đó tôi bấm vào một trình đơn khác và bấm lại, nó không hoạt động ... Bất kỳ ý tưởng làm thế nào tôi có thể sửa chữa nó? :) – Lara

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