Activity <App Name> telah membocorkan ServiceConnection <ServiceConnection Name> @ 438030a8 yang semula terikat di sini

134

Saya sedang mengerjakan aplikasi Android pertama saya. Saya punya tiga aktivitas di aplikasi saya, dan pengguna sering bolak-balik. Saya juga mendapat layanan jarak jauh, yang menangani koneksi telnet. Aplikasi harus mengikat ke layanan ini untuk mengirim / menerima pesan telnet.

Sunting Terima kasih BDLS atas jawaban informatif Anda. Saya telah menulis ulang kode saya sehubungan dengan klarifikasi Anda tentang perbedaan antara menggunakanbindService()sebagai fungsi yang berdiri sendiri atau setelahnyastartService(), dan saya sekarang hanya mendapatkan pesan kesalahan kebocoran sebentar-sebentar ketika menggunakan tombol kembali untuk menggilir kegiatan.

Aktivitas koneksi saya memiliki yang berikut onCreate()dan 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()

Jadi layanan dimulai ketika aktivitas dimulai, dan berhenti ketika aktivitas dihancurkan jika tidak ada koneksi telnet yang berhasil dibuat ( connectStatus == 0). Aktivitas lain mengikat layanan hanya jika koneksi berhasil dibuat ( connectStatus == 1, disimpan ke preferensi bersama). Inilah mereka onResume()dan 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()

Jadi pengikatan terjadi onResume()sehingga akan mengambil status yang diubah dari aktivitas koneksi, dan dalam onDestroy()fungsi itu tidak terikat, jika perlu.

Akhiri Edit

Tapi saya masih mendapatkan pesan kesalahan kebocoran memori "Aktivitas telah membocorkan ServiceConnection @ 438030a8 yang semula terikat di sini" sebentar-sebentar ketika berpindah kegiatan. Apa yang saya lakukan salah?

Terima kasih sebelumnya atas tips atau petunjuk !!!

Berikut pesan kesalahan lengkap (dari kode revisi):

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

Edit 2nd
Terima kasih sekali lagi bdl untuk saran Anda. Saya melakukan seperti yang Anda sarankan dan menambahkanonUnBind()penggantian ke layanan. onUnBind()sebenarnya hanya dipicu ketika semua klien memutuskan sambungan dari layanan, tetapi ketika saya menekan tombol home, itu dieksekusi, maka pesan kesalahan muncul! Ini tidak masuk akal bagi saya, karena semua klien telah terikat dari layanan, jadi bagaimana mungkin satu yang hancur membocorkan layanan Sambungan? Saksikan berikut ini:

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

Saya pikir itu mungkin seperti yang Anda katakan, di mana pengikatan ke layanan tidak lengkap ketika unbindService()dipanggil, namun saya mencoba memanggil metode pada layanan saat saya didukung melalui setiap aktivitas untuk memverifikasi bahwa pengikatan selesai, dan mereka semua pergi melalui denda.

Secara umum, perilaku ini tampaknya tidak terkait dengan berapa lama saya tinggal di setiap kegiatan. Namun, begitu aktivitas pertama bocor pada sambungan Layanan, mereka semua melakukan seperti yang saya lakukan setelahnya.

Satu hal lagi, jika saya mengaktifkan "Segera hancurkan kegiatan" di Dev Tools, itu mencegah kesalahan ini.

Ada ide?

catdotgif
sumber
Bisakah Anda menambahkan kode LightfactoryRemote.onCreate ()? (com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onCreate (LightfactoryRemote.java:97))
tbruyelle

Jawaban:

57

Anda belum memberikan kode apa pun dari Anda LightFactoryRemote, jadi ini hanya anggapan, tetapi sepertinya jenis masalah yang akan Anda lihat jika Anda menggunakan bindServicemetode itu sendiri.

Untuk memastikan layanan tetap berjalan, bahkan setelah aktivitas yang memulainya onDestroymemanggil metode, Anda harus terlebih dahulu menggunakannya startService.

Dokumen android untuk status startService :

Menggunakan startService () mengesampingkan masa berlaku layanan default yang dikelola oleh bindService (Intent, ServiceConnection, int): ini membutuhkan layanan untuk tetap berjalan sampai stopService (Intent) dipanggil, terlepas dari apakah ada klien yang terhubung dengannya.

Sedangkan untuk bindService :

Layanan akan dianggap diperlukan oleh sistem hanya selama konteks panggilan ada. Misalnya, jika Konteks ini adalah Kegiatan yang dihentikan, layanan tidak akan diminta untuk terus berjalan sampai Kegiatan dilanjutkan.


Jadi yang terjadi adalah aktivitas yang mengikat (dan karena itu memulai) layanan, telah dihentikan dan dengan demikian sistem berpikir layanan tidak lagi diperlukan dan menyebabkan kesalahan itu (dan kemudian mungkin menghentikan layanan).


Contoh

Dalam contoh ini layanan harus tetap berjalan terlepas dari apakah aktivitas panggilan berjalan.

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

Baris pertama memulai layanan, dan yang kedua mengikatnya ke aktivitas.

bdl
sumber
Saya memulai layanan menggunakan START_STICKY dan itu dimulai juga dengan niat booting. Jika saya menghubungi StartService, ia membuat instance layanan yang lain dan saya tidak ingin 2 layanan berjalan secara bersamaan. Bagaimana saya bisa memperbaiki kesalahan dalam hal ini?
opc0de
16
@ opc0de, tidak, Anda tidak membuat layanan lain ketika Anda memanggil startService () dua kali. Layanan secara logis adalah lajang. Tidak peduli berapa kali Anda memulainya, hanya satu layanan yang berjalan.
mahkie
2
Apa solusi untuk layanan lanjutan di latar belakang untuk pemutar musik?
Anand Savjani
45

Kamu bisa memakai:

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

    if (mServiceConn != null) {
        unbindService(mServiceConn);
    }
}
Mostafa Rostami
sumber
Luar biasa. Itulah itu.
Seltsam
31

Anda mengikat onResumetetapi tidak mengikat onDestroy. Anda harus melakukan unbinding in onPause, sehingga selalu ada pasangan panggilan bind / unbind yang cocok. Kesalahan terputus-putus Anda akan menjadi tempat aktivitas Anda dijeda tetapi tidak dihancurkan, dan kemudian dilanjutkan lagi.

Nick
sumber
13

Anda hanya perlu melepas ikatan layanan di onDestroy(). Lalu, peringatan itu akan pergi.

Lihat di sini .

Saat dokumen Aktivitas mencoba menjelaskan, ada tiga pengelompokan binding / unbind utama yang akan Anda gunakan: onCreate () dan onDestroy (), onStart () dan onStop (), dan onResume () dan onPause ().

pierrotlefou
sumber
7
seperti yang mungkin Anda alami di Destroy hampir tidak pernah dipanggil dari sistem operasi
martyglaubitz
Lihat di sini tautan ke depan untuk konten yang dilarang -> Peringatan Konten yang Dilarang. Adakah yang bisa mendapatkan akses? Tombol "Lanjutkan ke Grup" hanya menyegarkan halaman dan menunjukkan peringatan yang sama untuk saya.
Blaze Gawlik
11

Anda menyebutkan pengguna beralih di antara Aktivitas dengan cukup cepat. Mungkinkah Anda menelepon unbindServicesebelum koneksi layanan dibuat? Ini mungkin memiliki efek gagal mengikat, kemudian bocor ikatannya.

Tidak sepenuhnya yakin bagaimana Anda bisa menangani ini ... Mungkin ketika onServiceConnecteddipanggil Anda bisa menelepon unbindServicejika onDestroysudah dipanggil. Tidak yakin apakah itu akan berhasil.


Jika Anda belum melakukannya, Anda dapat menambahkan metode onUnbind ke layanan Anda. Dengan cara itu Anda bisa melihat dengan tepat ketika kelas Anda melepaskan ikatan dari itu, dan mungkin membantu dengan debugging.

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

Coba gunakan unbindService () di OnUserLeaveHint (). Ini mencegah skenario kebocoran ServiceConnection dan pengecualian lainnya.
Saya menggunakannya dalam kode saya dan berfungsi dengan baik.

Ashwini Shahapurkar
sumber
1

Anda bisa mengendalikannya dengan boolean, jadi Anda hanya memanggil unbind jika bind telah dibuat

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;
    }
}

Jika Anda hanya ingin melepaskan ikatannya jika sudah terhubung

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;
    }
};
D4rWiNS
sumber
0

Setiap layanan yang terikat dalam aktivitas harus tidak mengikat pada penutupan aplikasi.

Jadi coba gunakan

 onPause(){
   unbindService(YOUR_SERVICE);
   super.onPause();
 }
Punit
sumber
0

Saya telah membaca tentang Layanan Android baru-baru ini dan mendapat kesempatan untuk menyelam lebih dalam. Saya telah mengalami kebocoran layanan, untuk situasi saya itu terjadi karena saya memiliki Layanan tidak terikat yang memulai Layanan terikat , tetapi dalam hal ini Layanan tidak terikat saya digantikan oleh suatu Kegiatan .

Jadi ketika saya menghentikan Layanan tidak terikat saya dengan menggunakan stopSelf () kebocoran terjadi, alasannya adalah saya menghentikan layanan induk tanpa melepaskan ikatan layanan terikat. Sekarang layanan terikat sedang berjalan dan tidak tahu milik siapa itu.

Perbaikan yang mudah dan lurus ke depan adalah Anda harus memanggil unbindService (YOUR_SERVICE); dalam fungsi onDestroy () Anda dari Aktivitas / Layanan induk Anda. Dengan cara ini siklus hidup akan memastikan bahwa layanan terikat Anda dihentikan atau dibersihkan sebelum Aktivitas / Layanan induk Anda turun.

Ada satu variasi lain dari masalah ini. Terkadang di layanan terikat Anda, Anda ingin fungsi tertentu hanya berfungsi jika layanan terikat sehingga kami akhirnya menempatkan tanda terikat di onServiceConnected seperti:

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

Ini berfungsi dengan baik sampai di sini tetapi masalah muncul ketika kita memperlakukan fungsi onServiceDisconnected sebagai panggilan balik untuk panggilan fungsi unbindService , ini dengan dokumentasi hanya dipanggil ketika layanan terbunuh atau macet . Dan Anda tidak akan pernah mendapatkan panggilan balik ini di utas yang sama . Karenanya, kami akhirnya melakukan sesuatu seperti:

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

Yang menciptakan bug utama dalam kode karena bendera terikat kami tidak pernah disetel ulang ke false dan ketika layanan ini terhubung kembali sebagian besar kali itu true. Jadi untuk menghindari skenario ini, Anda harus mengatur boundke false saat Anda meneleponunbindService .

Ini dibahas lebih rinci di blog Erik .

Harapan yang pernah datang ke sini mendapat rasa penasarannya.

Farhaan Bukhsh
sumber
0

kesalahan ini terjadi ketika Anda akan mengikat layanan yang dibatasi. jadi, sol harus: -

  1. dalam koneksi layanan tambahkan serviceBound seperti di bawah ini:

    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. batalkan layanan padaDestroy

        if (serviceBound) {
            unbindService(serviceConnection);
        }
Atef Farouk
sumber