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?
sumber
Jawaban:
Anda belum memberikan kode apa pun dari Anda
LightFactoryRemote
, jadi ini hanya anggapan, tetapi sepertinya jenis masalah yang akan Anda lihat jika Anda menggunakanbindService
metode itu sendiri.Untuk memastikan layanan tetap berjalan, bahkan setelah aktivitas yang memulainya
onDestroy
memanggil metode, Anda harus terlebih dahulu menggunakannyastartService
.Dokumen android untuk status startService :
Sedangkan untuk bindService :
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.
Baris pertama memulai layanan, dan yang kedua mengikatnya ke aktivitas.
sumber
Kamu bisa memakai:
sumber
Anda mengikat
onResume
tetapi tidak mengikatonDestroy
. Anda harus melakukan unbinding inonPause
, 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.sumber
Anda hanya perlu melepas ikatan layanan di
onDestroy()
. Lalu, peringatan itu akan pergi.Lihat di sini .
sumber
Anda menyebutkan pengguna beralih di antara Aktivitas dengan cukup cepat. Mungkinkah Anda menelepon
unbindService
sebelum koneksi layanan dibuat? Ini mungkin memiliki efek gagal mengikat, kemudian bocor ikatannya.Tidak sepenuhnya yakin bagaimana Anda bisa menangani ini ... Mungkin ketika
onServiceConnected
dipanggil Anda bisa meneleponunbindService
jikaonDestroy
sudah 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.
sumber
Coba gunakan unbindService () di OnUserLeaveHint (). Ini mencegah skenario kebocoran ServiceConnection dan pengecualian lainnya.
Saya menggunakannya dalam kode saya dan berfungsi dengan baik.
sumber
Anda bisa mengendalikannya dengan boolean, jadi Anda hanya memanggil unbind jika bind telah dibuat
Jika Anda hanya ingin melepaskan ikatannya jika sudah terhubung
sumber
Setiap layanan yang terikat dalam aktivitas harus tidak mengikat pada penutupan aplikasi.
Jadi coba gunakan
sumber
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:
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:
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 mengaturbound
ke false saat Anda meneleponunbindService
.Ini dibahas lebih rinci di blog Erik .
Harapan yang pernah datang ke sini mendapat rasa penasarannya.
sumber
kesalahan ini terjadi ketika Anda akan mengikat layanan yang dibatasi. jadi, sol harus: -
dalam koneksi layanan tambahkan serviceBound seperti di bawah ini:
};
batalkan layanan padaDestroy
sumber