Hoạt động <Tên ứng dụng> đã bị rò rỉ ServiceConnection <Tên dịch vụ kết nối> @ 438030a8 ban đầu được ràng buộc tại đây


134

Tôi đang làm việc trên ứng dụng Android đầu tiên của mình. Tôi đã có ba hoạt động trong ứng dụng của mình và người dùng chuyển đổi qua lại khá thường xuyên. Tôi cũng đã có một dịch vụ từ xa, xử lý kết nối telnet. Các ứng dụng cần liên kết với dịch vụ này để gửi / nhận tin nhắn telnet.

Chỉnh sửa Cảm ơn bạn BDLS cho câu trả lời thông tin của bạn. Tôi đã viết lại mã của mình để làm rõ sự khác biệt giữa việc sử dụngbindService()như một chức năng độc lập hoặc sau đóstartService()và bây giờ tôi chỉ nhận được thông báo lỗi rò rỉ khi sử dụng nút quay lại để xoay vòng giữa các hoạt động.

Hoạt động kết nối của tôi có như sau onCreate()onDestroy():

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /*
     * Initialize the ServiceConnection.  Note that this is the only place startService() is run.
     * It is also the only time bindService is run without dependency on connectStatus.
     */
    conn = new TelnetServiceConnection();
    //start the service which handles telnet
    Intent i = new Intent();
    i.setClassName( "com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService" );
    startService(i);
    //bind to the service
    bindService(i, conn, 0);

    setContentView(R.layout.connect);
    setupConnectUI();

}//end OnCreate()

@Override
protected void onDestroy() {
    super.onDestroy();

    //unbind the service and null it out
    if (conn != null) {
        unbindService(conn);
        conn = null;
        }

    if(connectStatus == 0) {
        //stop the service
        Intent i = new Intent();
        i.setClassName( "com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService" );
        stopService(i);
        Log.d("LightfactoryRemote", "Connect onDestroy() attempted to stop service");
        }

    Log.d("LightfactoryRemote", "Connect onDestroy()");
    }//end onDestroy()

Vì vậy, dịch vụ được bắt đầu khi hoạt động được bắt đầu và dừng khi hoạt động bị hủy nếu không có kết nối telnet thành công nào được thực hiện ( connectStatus == 0). Các hoạt động khác liên kết với dịch vụ chỉ khi kết nối thành công được thực hiện ( connectStatus == 1, được lưu vào tùy chọn chia sẻ). Đây là của họ onResume()onDestroy():

@Override
protected void onResume() {
    super.onResume();

    //retrieve the shared preferences file, and grab the connectionStatus out of it.
    SharedPreferences settings = getSharedPreferences(PREFS_NAME, MODE_WORLD_WRITEABLE);
    connectStatus = settings.getInt("connectStatus", 0);

    Log.d("LightfactoryRemote", "Focus onResume with " + connectStatus);

    //if a telnet connection is active, start the service and bind to it
    if (connectStatus == 1) {
        conn = new TelnetServiceConnection();
        Intent i = new Intent();
        i.setClassName("com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService");
        bindService(i, conn, 0);
        //TODO write restore texview code
        }//end if
    }//end onResume

@Override
protected void onDestroy() {
    super.onDestroy();
    //unbind the service and null it out.
    if (conn != null) {
        Log.d("LightfactoryRemote", "Focus onDestroy() attempted to unbind service");
        unbindService(conn);
        conn = null;
        }
    Log.d("LightfactoryRemote", "Focus onDestroy()");
    }//end onDestroy()

Vì vậy, liên kết xảy ra onResume()để nó sẽ nhận trạng thái thay đổi từ hoạt động kết nối và trong onDestroy()chức năng, nó không bị ràng buộc, nếu cần thiết.

Kết thúc chỉnh sửa

Nhưng tôi vẫn nhận được thông báo lỗi rò rỉ bộ nhớ "Hoạt động đã bị rò rỉ ServiceConnection @ 438030a8 ban đầu bị ràng buộc ở đây" không liên tục khi chuyển đổi hoạt động. Tôi đang làm gì sai?

Cảm ơn trước cho bất kỳ lời khuyên hoặc con trỏ !!!

Thông báo lỗi đầy đủ sau (từ mã sửa đổi):

01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onStop()
01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onDestroy() attempted to unbind service
01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onDestroy()
01-02 22:04:26.672: ERROR/ActivityThread(2024): Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@439e51e8 that was originally bound here
01-02 22:04:26.672: ERROR/ActivityThread(2024): android.app.ServiceConnectionLeaked: Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@439e51e8 that was originally bound here
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:927)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:822)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ApplicationContext.bindService(ApplicationContext.java:842)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.content.ContextWrapper.bindService(ContextWrapper.java:319)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onResume(LightfactoryRemote.java:102)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1225)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.Activity.performResume(Activity.java:3559)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2838)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2866)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2420)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.access$2100(ActivityThread.java:116)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.os.Looper.loop(Looper.java:123)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at android.app.ActivityThread.main(ActivityThread.java:4203)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at java.lang.reflect.Method.invokeNative(Native Method)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at java.lang.reflect.Method.invoke(Method.java:521)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
01-02 22:04:26.672: ERROR/ActivityThread(2024):     at dalvik.system.NativeStart.main(Native Method)
01-02 22:04:26.692: WARN/ActivityManager(558): Unbind failed: could not find connection for android.os.BinderProxy@43c509a8

Chỉnh sửa lần thứ 2
Cảm ơn một lần nữa bdls cho đề xuất của bạn. Tôi đã làm như bạn đề xuất và thêmonUnBind()ghi đè vào dịch vụ. onUnBind()thực sự chỉ được kích hoạt khi tất cả các máy khách ngắt kết nối với dịch vụ, nhưng khi tôi nhấn nút home, nó sẽ thực thi, sau đó thông báo lỗi bật lên! Điều này không có ý nghĩa gì với tôi, vì tất cả các khách hàng đã không bị ràng buộc khỏi dịch vụ, vậy làm thế nào để phá hủy một dịch vụ kết nối? Kiểm tra xem nó:

01-03 19:38:30.837: DEBUG/LightfactoryRemote(1118): Focus onPause()1
01-03 19:38:31.577: WARN/IInputConnectionWrapper(1118): showStatusIcon on inactive InputConnection
01-03 19:38:31.587: DEBUG/LightfactoryRemote(1118): Focus onStop()
01-03 19:38:31.600: DEBUG/LightfactoryRemote(1118): Focus onDestroy() attempted to unbind service
01-03 19:38:31.607: DEBUG/LightfactoryRemote(1118): Focus onDestroy()
01-03 19:38:31.677: DEBUG/LightfactoryRemote(1125): TelnetService onUnBind()
01-03 19:38:31.727: ERROR/ActivityThread(1118): Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@435baeb0 that was originally bound here
01-03 19:38:31.727: ERROR/ActivityThread(1118): android.app.ServiceConnectionLeaked: Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@435baeb0 that was originally bound here
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:886)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:781)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ApplicationContext.bindService(ApplicationContext.java:820)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.content.ContextWrapper.bindService(ContextWrapper.java:307)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onResume(LightfactoryRemote.java:102)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1225)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.Activity.performResume(Activity.java:3530)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2619)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2647)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2287)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.access$1800(ActivityThread.java:112)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.os.Looper.loop(Looper.java:123)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at android.app.ActivityThread.main(ActivityThread.java:3948)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at java.lang.reflect.Method.invokeNative(Native Method)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at java.lang.reflect.Method.invoke(Method.java:521)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
01-03 19:38:31.727: ERROR/ActivityThread(1118):     at dalvik.system.NativeStart.main(Native Method)
01-03 19:38:31.777: WARN/ActivityManager(564): Unbind failed: could not find connection for android.os.BinderProxy@4370f8a8

Tôi nghĩ rằng nó có thể giống như bạn đã nói, khi ràng buộc với dịch vụ chưa hoàn tất khi unbindService()được gọi, tuy nhiên tôi đã thử gọi một phương thức trên dịch vụ khi tôi sao lưu qua từng hoạt động để xác minh rằng ràng buộc đã hoàn tất và tất cả đều đi qua phạt

Nói chung, hành vi này dường như không liên quan đến thời gian tôi ở trong mỗi hoạt động. Tuy nhiên, khi hoạt động đầu tiên rò rỉ dịch vụ Kết nối của nó, tất cả đều thực hiện khi tôi quay lại sau đó.

Một điều khác, nếu tôi bật "Hủy bỏ ngay lập tức các hoạt động" trong Dev Tools, nó sẽ ngăn chặn lỗi này.

Có ý kiến ​​gì không?


Bạn có thể thêm mã LightfactoryRemote.onCreate () không? (com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onCreate (LightfactoryRemote.java:97))
tbruyelle

Câu trả lời:


57

Bạn chưa cung cấp bất kỳ mã nào từ đó LightFactoryRemote, vì vậy đây chỉ là giả định, nhưng có vẻ như đây là loại vấn đề bạn gặp phải nếu bạn tự mình sử dụng bindServicephương thức này.

Để đảm bảo dịch vụ được duy trì hoạt động, ngay cả sau khi hoạt động bắt đầu có onDestroyphương thức được gọi, trước tiên bạn nên sử dụng startService.

Các tài liệu Android cho trạng thái startService :

Sử dụng startService () ghi đè tuổi thọ dịch vụ mặc định được quản lý bởi bindService (Intent, ServiceConnection, int): nó yêu cầu dịch vụ duy trì hoạt động cho đến khi stopService (Intent) được gọi, bất kể mọi máy khách có được kết nối với nó hay không.

Trong khi đó cho bindService :

Dịch vụ sẽ được xem xét theo yêu cầu của hệ thống miễn là bối cảnh cuộc gọi tồn tại. Ví dụ: nếu Bối cảnh này là một Hoạt động bị dừng, dịch vụ sẽ không được yêu cầu tiếp tục chạy cho đến khi Hoạt động được nối lại.


Vì vậy, những gì đã xảy ra là hoạt động ràng buộc (và do đó bắt đầu) dịch vụ, đã bị dừng và do đó hệ thống cho rằng dịch vụ không còn cần thiết và gây ra lỗi đó (và sau đó có thể dừng dịch vụ).


Thí dụ

Trong ví dụ này, dịch vụ nên được duy trì hoạt động bất kể hoạt động gọi có chạy hay không.

ComponentName myService = startService(new Intent(this, myClass.class));
bindService(new Intent(this, myClass.class), myServiceConn, BIND_AUTO_CREATE);

Dòng đầu tiên bắt đầu dịch vụ và dòng thứ hai liên kết nó với hoạt động.


Tôi bắt đầu dịch vụ bằng START_STICKY và nó cũng bắt đầu bằng mục đích khởi động. Nếu tôi gọi StartService, nó sẽ tạo một phiên bản khác của dịch vụ và tôi không muốn 2 dịch vụ chạy cùng một lúc. Làm thế nào tôi có thể sửa lỗi trong trường hợp này?
opc0de

16
@ opc0de, không, bạn không tạo dịch vụ khác khi bạn gọi startService () hai lần. Các dịch vụ là đơn lẻ theo bản chất. Cho dù bạn khởi động bao nhiêu lần, chỉ một dịch vụ chạy.
mahkie

2
Giải pháp cho dịch vụ tiếp tục trong nền cho trình phát nhạc là gì?
Anand Savć

45

Bạn có thể dùng:

@Override
public void onDestroy() {
    super.onDestroy();

    if (mServiceConn != null) {
        unbindService(mServiceConn);
    }
}

Thông minh. Đó là những gì nó được.
Seltsam

31

Bạn liên kết trong onResumenhưng không ràng buộc trong onDestroy. onPauseThay vào đó, bạn nên thực hiện hủy liên kết để luôn có các cặp liên kết / liên kết không khớp. Các lỗi không liên tục của bạn sẽ là nơi hoạt động của bạn bị tạm dừng nhưng không bị phá hủy và sau đó được tiếp tục lại.


13

Bạn chỉ cần hủy liên kết dịch vụ trong onDestroy(). Sau đó, Cảnh báo sẽ đi.

Xem ở đây .

Khi tài liệu Activity cố gắng giải thích, có ba nhóm liên kết / hủy liên kết chính mà bạn sẽ sử dụng: onCreate () và onDestroy (), onStart () và onStop () và onResume () và onPause ().


7
như bạn có thể có kinh nghiệm trênDestroy gần như không bao giờ được gọi từ hệ điều hành
martyglaubitz

Xem ở đây liên kết chuyển tiếp đến nội dung bị cấm -> Cảnh báo nội dung bị cấm. Bất cứ ai cũng có thể truy cập? Nút "Tiếp tục nhóm" chỉ làm mới trang và hiển thị cảnh báo tương tự cho tôi.
Blaze Gawlik

11

Bạn đề cập đến việc người dùng chuyển đổi giữa các hoạt động khá nhanh chóng. Có thể là bạn đang gọi unbindServicetrước khi kết nối dịch vụ được thiết lập? Điều này có thể có tác dụng của việc không hủy liên kết, sau đó rò rỉ các ràng buộc.

Không hoàn toàn chắc chắn làm thế nào bạn có thể xử lý việc này ... Có lẽ khi onServiceConnectedđược gọi bạn có thể gọi unbindServicenếu onDestroyđã được gọi. Không chắc chắn nếu điều đó sẽ làm việc mặc dù.


Nếu bạn chưa có, bạn có thể thêm phương thức onUnbind vào dịch vụ của mình. Bằng cách đó bạn có thể thấy chính xác khi các lớp của bạn hủy liên kết với nó và nó có thể giúp gỡ lỗi.

@Override
public boolean onUnbind(Intent intent) {
    Log.d(this.getClass().getName(), "UNBIND");
    return true;
}

2

Hãy thử sử dụng unbindService () trong OnUserLeaveHint (). Nó ngăn chặn kịch bản rò rỉ ServiceConnection và các ngoại lệ khác.
Tôi đã sử dụng nó trong mã của tôi và hoạt động tốt.


1

Bạn chỉ có thể điều khiển nó bằng boolean, vì vậy bạn chỉ gọi unbind nếu liên kết đã được thực hiện

public void doBindService()
{
    if (!mIsBound)
    {
        bindService(new Intent(this, DMusic.class), Scon, Context.BIND_AUTO_CREATE);
        mIsBound = true;
    }
}

public void doUnbindService()
{
    if (mIsBound)
    {
        unbindService(Scon);
        mIsBound = false;
    }
}

Nếu bạn chỉ muốn hủy liên kết nó nếu nó đã được kết nối

public ServiceConnection Scon = new ServiceConnection() {

    public void onServiceConnected(ComponentName name, IBinder binder)
    {
        mServ = ((DMusic.ServiceBinder) binder).getService();
        mIsBound = true;
    }

    public void onServiceDisconnected(ComponentName name)
    {
        mServ = null;
    }
};

0

Mọi dịch vụ bị ràng buộc trong hoạt động phải được hủy liên kết trên ứng dụng.

Vì vậy, hãy thử sử dụng

 onPause(){
   unbindService(YOUR_SERVICE);
   super.onPause();
 }

0

Gần đây tôi đã đọc về Dịch vụ Android và có cơ hội tìm hiểu sâu về nó. Tôi đã gặp phải một rò rỉ dịch vụ, vì tình huống của tôi đã xảy ra do tôi có một Dịch vụ không ràng buộc đang bắt đầu một Dịch vụ bị ràng buộc , nhưng trong Dịch vụ không liên kết này của tôi được thay thế bằng một Hoạt động .

Vì vậy, khi tôi dừng Dịch vụ không liên kết của mình bằng cách sử dụng stopSelf () thì sự rò rỉ xảy ra, lý do là tôi đã dừng phụ huynh dịch vụ mà không ràng buộc dịch vụ bị ràng buộc. Bây giờ dịch vụ ràng buộc đang chạy và nó không biết nó thuộc về ai.

Cách khắc phục dễ dàng và đơn giản là bạn nên gọi unbindService (YOU_SERVICE); trong onDestroy () của bạn của Hoạt động / Dịch vụ gốc của bạn. Bằng cách này, vòng đời sẽ đảm bảo rằng các dịch vụ bị ràng buộc của bạn bị dừng hoặc dọn sạch trước khi Hoạt động / Dịch vụ của cha mẹ bạn bị hỏng.

Có một biến thể khác của vấn đề này. Đôi khi, trong dịch vụ bị ràng buộc của bạn, bạn muốn một số chức năng nhất định chỉ hoạt động nếu dịch vụ bị ràng buộc để cuối cùng chúng tôi đặt một cờ bị ràng buộc trong onServiceConnected như:

public void onServiceConnected(ComponentName name, IBinder service) {
            bounded = true;
            // code here
        }

Điều này hoạt động tốt cho đến đây nhưng vấn đề xảy ra khi chúng ta coi hàm onServiceDisconnected là một cuộc gọi lại cho lệnh gọi hàm unbindService , điều này bởi tài liệu chỉ được gọi khi một dịch vụ bị giết hoặc bị hỏng . Và bạn sẽ không bao giờ có được cuộc gọi lại này trong cùng một chủ đề . Do đó, chúng tôi cuối cùng đã làm một cái gì đó như:

public void onServiceDisconnected(ComponentName name) {
            bounded = false;
        }

Điều này tạo ra lỗi lớn trong mã bởi vì cờ bị ràng buộc của chúng tôi không bao giờ được đặt lại thành false và khi dịch vụ này được kết nối lại hầu hết các lần true. Vì vậy, để tránh trường hợp này, bạn nên đặt thành boundsai thời điểm bạn đang gọi unbindService.

Đây là trang bìa chi tiết hơn trong blog của Erik .

Hy vọng ai từng đến đây đã thỏa mãn trí tò mò của anh.


0

lỗi này xảy ra khi bạn định ràng buộc một dịch vụ bị ràng buộc. vì vậy, sol nên là: -

  1. trong kết nối dịch vụ thêm serviceBound như dưới đây:

    private final ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // your work here.
    
        serviceBound = true;
    
    }
    
    @Override
    public void onServiceDisconnected(ComponentName name) {
    
        serviceBound = false;
    }

    };

  2. hủy liên kết dịch vụ trênDestroy

        if (serviceBound) {
            unbindService(serviceConnection);
        }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.