ผูกบริการกับกิจกรรมใน Android


91

ฉันกำลังพยายามเขียนโปรแกรมเล่นสื่อง่ายๆที่เล่นเสียงสตรีมมิ่งโดยใช้ RTSP ฉันมีกิจกรรม GUI และบริการที่ดำเนินการเล่น คำถามของฉันคือทำอย่างไรจึงจะสื่อสารระหว่างกิจกรรมและบริการได้ดีที่สุด (เช่นการอัปเดต GUI ตามสถานะของผู้เล่น)

ฉันรู้ว่าฉันสามารถผูกบริการกับกิจกรรมโดยใช้ onBind () ได้ แต่ถ้าฉันเข้าใจถูกต้องสิ่งนี้จะหยุดบริการหากกิจกรรมถูกฆ่า ฉันต้องการเล่นต่อแม้ว่าผู้ใช้จะออกจากกิจกรรมแล้วก็ตาม มีมาตรฐานหรือวิธีที่ต้องการในการจัดการกับปัญหานี้หรือไม่?

คำตอบ:


155

"หากคุณเริ่มบริการ Android ด้วยstartService(..)บริการนั้นจะยังคงทำงานต่อไปจนกว่าคุณจะเรียกใช้อย่างชัดเจนstopService(..)มีเหตุผลสองประการที่ระบบสามารถเรียกใช้บริการได้หากมีคนโทรContext.startService()เข้าระบบจะดึงข้อมูลบริการ (สร้างและเรียกonCreate()ใช้เมธอดหาก จำเป็น) จากนั้นเรียกonStartCommand(Intent, int, int)ใช้เมธอดด้วยอาร์กิวเมนต์ที่ไคลเอ็นต์ให้มาบริการจะทำงานต่อไปจนกว่าจะมีการเรียกContext.stopService()หรือstopSelf()ถูกเรียกโปรดทราบว่าการเรียกหลายครั้งที่Context.startService()จะไม่ซ้อนกัน (แม้ว่าจะส่งผลให้มีการเรียกที่ตรงกันหลายครั้งonStartCommand()) ดังนั้นจึงไม่มี ไม่ว่าจะเริ่มบริการกี่ครั้งก็ตามจะหยุดบริการหนึ่งครั้งContext.stopService()หรือวิธีการเพื่อให้แน่ใจว่าบริการจะไม่หยุดจนกว่าจะมีการประมวลผล Intent เริ่มต้น stopSelf()ถูกเรียกอย่างไรก็ตามบริการต่างๆสามารถใช้บริการได้stopSelf(int)

ไคลเอ็นต์ยังสามารถใช้Context.bindService()เพื่อรับการเชื่อมต่อแบบถาวรกับบริการ นี้เช่นเดียวกันสร้างบริการถ้าไม่ได้ทำงานแล้ว (เรียกonCreate()ในขณะที่การทำเช่นนั้น) onStartCommand()แต่ไม่ได้โทร ไคลเอนต์จะได้รับIBinderออบเจ็กต์ที่บริการส่งคืนจากonBind(Intent)เมธอดของมันทำให้ไคลเอนต์สามารถโทรกลับไปที่บริการได้ บริการจะยังคงทำงานตราบเท่าที่มีการสร้างการเชื่อมต่อ (ไม่ว่าไคลเอ็นต์จะยังคงมีการอ้างอิงในบริการหรือไม่IBinderก็ตาม) โดยปกติการIBinderส่งคืนจะเป็นของอินเทอร์เฟซที่ซับซ้อนซึ่งถูกเขียนใน AIDL

บริการสามารถเริ่มต้นและเชื่อมต่อกับบริการได้ ในกรณีเช่นนี้ระบบจะให้บริการทำงานต่อไปตราบเท่าที่เริ่มทำงานหรือมีการเชื่อมต่ออย่างน้อยหนึ่งรายการกับContext.BIND_AUTO_CREATEแฟล็ก เมื่อสถานการณ์เหล่านี้ไม่เกิดขึ้นระบบonDestroy()จะเรียกใช้วิธีการของบริการและบริการจะสิ้นสุดลงอย่างมีประสิทธิภาพ การทำความสะอาดทุกชนิด (หยุดกระทู้, ยกเลิกการลงทะเบียนรับ) ควรจะเสร็จสมบูรณ์เมื่อกลับมาจากonDestroy()."


1
ความสับสนเล็กน้อย: หากกิจกรรมถูกทำลายบริการจะถูกทำลายด้วยหรือไม่? หรือบริการนั้นจะไม่ถูกทำลายหากฉันใช้ AIDL ของตัวเองเท่านั้น? ฉันถามเพราะเมื่อฉันใช้ startService (โดยเฉพาะใน IntentService) บริการจะหยุดเมื่อทำงานเสร็จเมื่อเทียบกับเมื่อกิจกรรมตาย เป็นความจริงหรือไม่ที่หากกิจกรรมนั้นตายบริการที่ผูกมัด (โดยเฉพาะ) ก็ตายด้วยเช่นกัน
Katedral Pillon

1
หากคุณใช้เซิร์ฟเวอร์ธรรมดาโดยเรียก startService บริการจะไม่หยุดจนกว่าคุณจะเรียก stopSelf () หรือ stopService () และถัดไปถ้าคุณใช้ bindService บริการใช่จะตายหากส่วนประกอบที่เชื่อมต่อ / ผูกทั้งหมดทำลาย
Asif Mushtaq

1
@UnKnown หากบริการเริ่มต้นโดยใช้ startService () ไม่ว่าคุณจะผูกหรือเลิกผูกบริการจะยังคงทำงานต่อไปและสามารถทำลายได้โดยการเรียกใช้ stopService () หรือ stopSelf () เท่านั้น ดังนั้นแม้ว่ากิจกรรมที่ผูกพันกับบริการจะถูกทำลายบริการก็จะไม่ถูกทำลาย
CopsOnRoad

คุณช่วยฉันด้วยคำถามนี้ได้ไหมstackoverflow.com/questions/51508046/…
Rajesh K

25

ก่อนอื่น 2 สิ่งที่เราต้องเข้าใจ

ลูกค้า

  • ส่งคำขอไปยังเซิร์ฟเวอร์เฉพาะ

    bindService(new 
        Intent("com.android.vending.billing.InAppBillingService.BIND"),
            mServiceConn, Context.BIND_AUTO_CREATE);`
    

นี่mServiceConnคืออินสแตนซ์ของServiceConnectionคลาส (inbuilt) ซึ่งเป็นอินเทอร์เฟซที่เราต้องใช้สองวิธี (ที่ 1 สำหรับเครือข่ายที่เชื่อมต่อและเครือข่ายที่ 2 ไม่ได้เชื่อมต่อ) เพื่อตรวจสอบสถานะการเชื่อมต่อเครือข่าย

เซิร์ฟเวอร์

  • จัดการคำขอของไคลเอนต์และสร้างแบบจำลองของตัวเองซึ่งเป็นแบบส่วนตัวสำหรับลูกค้าที่ส่งคำขอเท่านั้นและเซิร์ฟเวอร์จำลองนี้ทำงานบนเธรดที่แตกต่างกัน

ตอนนี้ที่ฝั่งไคลเอ็นต์จะเข้าถึงวิธีการทั้งหมดของเซิร์ฟเวอร์ได้อย่างไร?

  • เซิร์ฟเวอร์ส่งการตอบกลับด้วย IBind Object.so อ็อบเจ็กต์ IBind คือตัวจัดการของเราซึ่งเข้าถึงเมธอดบริการทั้งหมดโดยใช้ตัวดำเนินการ (.)

    MyService myService;
    public ServiceConnection myConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder binder) {
            Log.d("ServiceConnection","connected");
            myService = binder;
        }
        //binder comes from server to communicate with method's of 
    
        public void onServiceDisconnected(ComponentName className) {
            Log.d("ServiceConnection","disconnected");
            myService = null;
        }
    }
    

ตอนนี้วิธีการโทรที่อยู่ในบริการ

myservice.serviceMethod();

นี่myServiceคือวัตถุและserviceMethodeเป็นวิธีการในการให้บริการ และด้วยวิธีนี้การสื่อสารระหว่างไคลเอนต์และเซิร์ฟเวอร์


10

ฉันพยายามโทร

startService(oIntent);
bindService(oIntent, mConnection, Context.BIND_AUTO_CREATE);

ดังนั้นและฉันสามารถสร้างบริการที่เหนียวและเชื่อมโยงกับมันได้ รายละเอียดการสอนสำหรับBound ตัวอย่างบริการ


5

มีวิธีที่เรียกว่าunbindServiceซึ่งจะใช้ ServiceConnection ซึ่งคุณจะสร้างขึ้นเมื่อเรียกใช้ bindService วิธีนี้จะช่วยให้คุณสามารถยกเลิกการเชื่อมต่อกับบริการได้ในขณะที่ยังคงทำงานอยู่

สิ่งนี้อาจก่อให้เกิดปัญหาเมื่อคุณเชื่อมต่ออีกครั้งเนื่องจากคุณอาจไม่รู้ว่ากำลังทำงานอยู่หรือไม่เมื่อคุณเริ่มกิจกรรมอีกครั้งดังนั้นคุณจะต้องพิจารณาสิ่งนั้นในรหัสกิจกรรมของคุณ

โชคดี!


-1

นี่เป็นคำตอบที่มีอคติ แต่ฉันเขียนไลบรารีที่อาจทำให้การใช้บริการ Android ง่ายขึ้นหากพวกเขาทำงานในกระบวนการเดียวกับแอป: https://github.com/germnix/acacia

โดยทั่วไปคุณกำหนดอินเทอร์เฟซที่มีคำอธิบายประกอบด้วย @Service และคลาสการนำไปใช้งานและไลบรารีจะสร้างและผูกบริการจัดการการเชื่อมต่อและเธรดผู้ปฏิบัติงานเบื้องหลัง:

@Service(ServiceImpl.class)
public interface MyService {
    void doProcessing(Foo aComplexParam);
}

public class ServiceImpl implements MyService {
    // your implementation
}

MyService service = Acacia.createService(context, MyService.class);
service.doProcessing(foo);

<application
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">
    ...
    <service android:name="com.gmr.acacia.AcaciaService"/>
    ...
</application>

คุณสามารถรับอินสแตนซ์ของ android.app.Service ที่เกี่ยวข้องเพื่อซ่อน / แสดงการแจ้งเตือนแบบต่อเนื่องใช้ android.app.Service ของคุณเองและจัดการเธรดด้วยตนเองหากคุณต้องการ


-5

หากผู้ใช้สำรองข้อมูลonDestroy()จะเรียกใช้เมธอด วิธีนี้เป็นการหยุดบริการใด ๆ ที่ใช้ในแอปพลิเคชัน onDestroy()ดังนั้นถ้าคุณต้องการที่จะดำเนินการให้บริการแม้ว่าหลังผู้ใช้ออกจากแอพลิเคชันเพียงแค่ลบ หวังว่าจะช่วยได้


คุณจะต้องแทนที่ฟังก์ชันและลบการเรียกเริ่มต้นไปยัง onDestroy () ของ superclass หาก IDE ของคุณสร้างขึ้นโดยอัตโนมัติ แต่ทำไมคุณถึงอยากทำเช่นนี้?
Riptyde4
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.