2015-04-17 16 views
5

Tôi là một người mới bắt đầu với Java và đã tạo ra một đoạn mã Java đơn giản, trong đó trong Runnable sau 1,5 giây, tôi thay đổi TextView từ Hello World thành Hola Mundo. Nó hoạt động hoàn hảo, về cơ bản một WeakReference nên ngăn chặn rò rỉ bộ nhớ này xảy ra đúng không? Tôi có một nghi ngờ nếu có hoàn toàn không có rò rỉ bộ nhớ bất cứ khi nào định hướng thiết bị xảy ra. Tôi rất thích kiểm tra điều này nhưng không thể xoay sở để thay đổi định hướng trong Android mô phỏng của tôi.Đây có phải là Runnable an toàn do rò rỉ bộ nhớ không?

Đây là mã:

package com.example.helloworld; 

import android.app.Activity; 
import android.os.Bundle; 
import android.os.Handler; 
import android.widget.TextView; 
import android.util.Log; 
import java.lang.ref.WeakReference; 

public class HelloWorldActivity extends Activity 
{ 
    private Handler h = new Handler(); 
    private static TextView txtview; 
    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     txtview = (TextView) findViewById(R.id.mainview); 

     h.postDelayed(new WeakRunnable(txtview),1500); 
    } 

    private static final class WeakRunnable implements Runnable { 
     private final WeakReference<TextView> mtextview; 

     protected WeakRunnable(TextView textview){ 
      mtextview = new WeakReference<TextView>(textview); 
     } 

      @Override 
      public void run() { 
       TextView textview = mtextview.get(); 
       if (textview != null) { 
        txtview.setText("Hola Mundo"); 
        textview = null; // No idea if setting to null afterwards is a good idea 
       } 
       Log.d("com.example.helloworld", "" + textview); 
      } 
    }   

} 

EDIT

Đó là an toàn từ rò rỉ bộ nhớ nhưng một vài câu trả lời cũng được quan tâm với thread UI chặn. Trong thực tế, mã này chạy Trình xử lý trong luồng chính (UI). Để đẻ trứng một chủ đề mới Tôi đang đẻ trứng một sợi thủ công như sau:

package com.example.helloworld; 

import android.app.Activity; 
import android.os.Bundle; 
import android.os.Handler; 
import android.widget.TextView; 
import android.util.Log; 
import java.lang.ref.WeakReference; 

public class HelloWorldActivity extends Activity 
{ 

    private static TextView txtview; 
    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     txtview = (TextView) findViewById(R.id.mainview); 

     Thread t = new Thread(new WeakRunnable(txtview)); 
     t.start(); 
    } 

    private static final class WeakRunnable implements Runnable { 
     private final WeakReference<TextView> mtextview; 

     protected WeakRunnable(TextView textview){ 
      mtextview = new WeakReference<TextView>(textview); 
     } 

      @Override 
      public void run() { 
       TextView textview = mtextview.get(); 
       if (textview != null) { 
        /* 
        try { 
         Thread.sleep(1500); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
        */ 
        txtview.setText("Hola Mundo"); 
        textview = null; 
       } 
       Log.d("com.example.helloworld", "" + Thread.currentThread().getName()); // Outputs "Thread-<num>" if not running on UI thread 
      } 
    }   

} 

Vấn đề bây giờ là tôi dường như không thể trì hoãn thread sinh ra trong bất kỳ cách nào, nếu không nó hoạt động.

này:

try { 
    Thread.sleep(1500); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} 

làm cho các ứng dụng bỏ bản thân và tôi không hiểu tại sao. Một cái gì đó nói với tôi tôi đang trì hoãn nó một cách sai lầm.

EDIT2

Nhờ có sự liên kết @EugenMatynov cho tôi: update ui from another thread in android tôi đã hiểu tại sao các ứng dụng bỏ hoạt. Tất cả đều đi xuống lý do Bạn không thể gọi các phương thức giao diện người dùng từ các chủ đề khác ngoài chuỗi chính. và thực tiễn không tốt để cập nhật giao diện người dùng từ một chuỗi khác.

+2

sạch xử lý của hàng đợi trên onPause, và bạn đang bị rò rỉ 100% miễn phí. Trong trường hợp này. – Blackbelt

+1

Không có rò rỉ bộ nhớ nào trong trường văn bản tĩnh? – stevehs17

Trả lời

3

Tôi nghĩ rằng mã của bạn là bị rò rỉ miễn phí nếu bạn sử dụng:

private static Handler h = new Handler(); 

hoặc

txtview.postDelayed(new WeakRunnable(txtview),1500); 

vì bạn đã được lưu trữ quan điểm như một WeakReference. phương pháp:

txtview.postDelayed(new WeakRunnable(txtview),1500); 

chỉ cần gọi xử lý chính của chuỗi giao diện người dùng để nếu hoạt động bị hủy thì chế độ xem là rỗng và không thể chạy liều nào.

cũng vì sự yếu kém, hoạt động có thể được thu thập rác do không có tham chiếu mạnh mẽ đến nó.

+0

Sau khi bạn chấp nhận câu trả lời của tôi một lần nữa tôi xem xét câu trả lời của tôi và câu hỏi của bạn và tìm thấy một lỗi trong câu trả lời của tôi, câu trả lời của tôi chỉ hợp lệ nếu bạn sử dụng 'private static Handler h = new Handler(); 'txtview.postDelayed (new WeakRunnable (txtview), 1500);' bạn có thể chấp nhận trả lời blackbeltt hoặc cho phép tôi chỉnh sửa nó. cũng lưu ý rằng chạy một runnable bởi sự chậm trễ là khác nhau từ ngủ trên thread chính. bởi vì tôi nghĩ mọi người khiến bạn bối rối :-) – mmlooloo

+0

Sự khác biệt giữa phiên bản tĩnh và không tĩnh là gì? –

+0

OK, giải thích tốt đẹp. Tôi khá mới với Java vì vậy tôi phải bấm vào một số khái niệm. Tôi đã chọn 'txtview.postDelayed (new WeakRunnable (txtview), 1500);' vì nó trông dễ dàng hơn và chiếm không gian thị giác tương đối ít hơn. Vui lòng chỉnh sửa câu trả lời của bạn :) –

2

h.postDelayed (new WeakRunnable (txtview), 1500); Tôi nghĩ rằng nó sẽ chặn UI Thread. đây là một mẫu tốt cho rò rỉ bộ nhớ. https://github.com/badoo/android-weak-handler

+1

bạn có thể thêm mã có liên quan vào câu trả lời và nơi mã được đề cập có thể được cải thiện không? –

+4

* Tôi nghĩ rằng nó sẽ chặn UI Thread *. Không nó không. – Blackbelt

+0

Nó sẽ không chặn giao diện người dùng, cũng như mã là chính xác cùng một mã được viết trong blog liên quan đến thư viện https://techblog.badoo.com/blog/2014/08/28/android-handler-memory-leaks –

3

Tôi có một nghi ngờ nếu có hoàn toàn không có rò rỉ bộ nhớ bất cứ khi nào thiết bị hướng xảy ra.

Có thể. Trong 1,5 giây. Sau khi hàng đợi được dọn sạch, trình xử lý có thể được thu thập rác và cũng là Hoạt động cũ. Để được an toàn ghi đè onPause, và gọi handler.removeCallbacks(null); để xóa hàng đợi của Handler

+2

Trong trường hợp của tôi, tôi đã phải gọi 'handler.removeCallbacksAndMessages (null);', vì thực hiện phiên bản android 23, 'removeCallbacks();' không làm gì khi bạn truyền null thành tham số (xem 'removeMessages của MessageQueue() ; '). –

+0

@MateusGondim cảm ơn cho các tip – Blackbelt

1

Hãy làm điều này, nếu không bạn sẽ chặn UIThread và không được khuyến nghị. Để làm điều này, bạn cũng có thể sử dụng một TimerTask, kiểm tra xem nó ở đây: http://developer.android.com/reference/java/util/TimerTask.html

import android.widget.TextView; 
import android.util.Log; 
import java.lang.ref.WeakReference; 

public class HelloWorldActivity extends Activity 
{ 
    private Handler h = new Handler(); 
    private static TextView txtview; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     txtview = (TextView) findViewById(R.id.mainview);   

     h.postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       changeText(); 
      } 
     }, 1500); 
    } 

    public void changeText(){ 
     txtview.setText("Hola mundo."); 
     h.removeCallbacksAndMessages(null); 
    }   

} 

Bằng cách này, bạn có thể thay đổi định hướng trong giả lập của bạn theo cách này: Ctrl + F12

+0

** Lớp tĩnh bên trong có thể tạo rò rỉ bộ nhớ khi mã của bạn chính xác thực hiện: -) ** – mmlooloo

+0

Tôi đã chỉnh sửa mã, có thể xóa cuộc gọi lại và tin nhắn sẽ làm cho mã ít nhạy cảm hơn với việc gây ra rò rỉ bộ nhớ. Bạn nghĩ sao? – Grender

+1

rò rỉ của bạn được gây ra bằng cách sử dụng Runnable mới(), thực sự mã OP là chính xác, bạn có thể loại bỏ callback tại onPause nhưng có thể là liều OP không thích điều đó vì ví dụ người dùng nhấn nút home và sau 2s quay lại ứng dụng để anh ấy muốn thấy thay đổi. – mmlooloo

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