วิธีการให้บริการ Android สื่อสารกับกิจกรรม


251

ฉันกำลังเขียนแอปพลิเคชัน Android เครื่องแรกของฉันและพยายามทำให้การสื่อสารระหว่างบริการและกิจกรรมเป็นไปอย่างราบรื่น ฉันมีบริการที่จะทำงานในพื้นหลังและทำการบันทึกผ่าน gps และเวลา ฉันจะมีกิจกรรมที่จะใช้ในการเริ่มและหยุดบริการ

ดังนั้นก่อนอื่นฉันต้องสามารถทราบได้ว่าบริการกำลังทำงานอยู่หรือไม่เมื่อเริ่มกิจกรรม มีคำถามอื่น ๆ เกี่ยวกับที่นี่ดังนั้นฉันคิดว่าฉันสามารถหาได้ (แต่อย่าลังเลที่จะให้คำแนะนำ)

ปัญหาที่แท้จริงของฉัน: หากกิจกรรมกำลังทำงานอยู่และบริการเริ่มต้นขึ้นฉันต้องการวิธีที่บริการในการส่งข้อความไปยังกิจกรรม Simple Strings และ integers ณ จุดนี้ - ข้อความสถานะส่วนใหญ่ ข้อความจะไม่เกิดขึ้นเป็นประจำดังนั้นฉันจึงไม่คิดว่าการให้บริการเป็นวิธีที่ดีในการไปหากมีวิธีอื่น ฉันต้องการการสื่อสารนี้เฉพาะเมื่อผู้ใช้เริ่มต้นกิจกรรม - ฉันไม่ต้องการเริ่มกิจกรรมจากบริการ กล่าวอีกนัยหนึ่งถ้าคุณเริ่มกิจกรรมและบริการกำลังทำงานคุณจะเห็นข้อความสถานะใน UI กิจกรรมเมื่อสิ่งที่น่าสนใจเกิดขึ้น หากคุณไม่เริ่มกิจกรรมคุณจะไม่เห็นข้อความเหล่านี้ (ไม่น่าสนใจ)

ดูเหมือนว่าฉันควรจะสามารถตรวจสอบว่าบริการกำลังทำงานอยู่หรือไม่และถ้าเป็นเช่นนั้นให้เพิ่มกิจกรรมเป็นผู้ฟัง จากนั้นลบกิจกรรมเป็นผู้ฟังเมื่อกิจกรรมหยุดชั่วคราวหรือหยุด เป็นไปได้จริงเหรอ? วิธีเดียวที่ฉันสามารถคิดได้ว่าจะให้กิจกรรมใช้ Parcelable และสร้างไฟล์ AIDL เพื่อให้ฉันสามารถส่งผ่านอินเทอร์เฟซระยะไกลของบริการได้ แม้ว่าจะดูเหมือน overkill และฉันก็ไม่รู้ว่า Activity ควรใช้ writeToParcel () / readFromParcel () อย่างไร

มีวิธีที่ง่ายหรือดีกว่า ขอบคุณสำหรับความช่วยเหลือ

แก้ไข:

สำหรับผู้ที่มีความสนใจในภายหลังจะมีรหัสตัวอย่างจาก Google สำหรับจัดการสิ่งนี้ผ่าน AIDL ในไดเรกทอรีตัวอย่าง: /apis/app/RemoteService.java

คำตอบ:


94

การสื่อสารกับบริการมีสามวิธีที่ชัดเจน:

  1. การใช้เจตจำนง
  2. ใช้ AIDL
  3. การใช้เซอร์วิสอ็อบเจ็กต์เอง (เป็น singleton)

ในกรณีของคุณฉันจะไปกับตัวเลือก 3 ทำการอ้างอิงแบบคงที่กับบริการด้วยตนเองและเติมใน onCreate ():

void onCreate(Intent i) {
  sInstance = this;
}

ทำให้ฟังก์ชั่นแบบคงที่ซึ่งผลตอบแทนคงMyService getInstance()sInstance

จากนั้นเมื่อActivity.onCreate()คุณเริ่มบริการให้รอแบบอะซิงโครนัสจนกว่าบริการจะเริ่มขึ้นจริง (คุณสามารถให้บริการของคุณแจ้งแอปของคุณว่ามันพร้อมแล้วโดยส่งเจตนาเข้าร่วมกิจกรรม) และรับอินสแตนซ์ของมัน เมื่อคุณมีอินสแตนซ์ให้ลงทะเบียนออบเจ็กต์ฟังฟังบริการของคุณและคุณตั้งค่าไว้ หมายเหตุ: เมื่อมีการแก้ไขภายในชมกิจกรรมที่คุณควรปรับเปลี่ยนพวกเขาในหัวข้อ UI, Activity.runOnUiThread()บริการอาจจะทำงานกระทู้ของตัวเองดังนั้นคุณต้องโทร

สิ่งสุดท้ายที่คุณต้องทำคือการลบการอ้างอิงไปยังวัตถุฟังคุณActivity.onPause()มิฉะนั้นตัวอย่างของบริบทกิจกรรมของคุณจะรั่วไหลไม่ดี

หมายเหตุ: วิธีการนี้มีประโยชน์เฉพาะเมื่อแอปพลิเคชัน / กิจกรรม / งานของคุณเป็นกระบวนการเดียวที่จะเข้าถึงบริการของคุณ หากไม่ใช่กรณีนี้คุณต้องใช้ตัวเลือก 1 หรือ 2


2
ฉันจะbusy-waitทำกิจกรรมได้อย่างไร คุณช่วยอธิบายได้มั้ย
iTurki

1
ดังนั้นหลังจาก onCreate หรือหลังจาก onStartCommand ในคลาสบริการของคุณตั้งค่าตัวแปรสแตติกสาธารณะเรียกว่า isConnected หรือบางสิ่งบางอย่างเป็นจริง จากนั้นในกิจกรรมของคุณให้ทำดังนี้: เจตนาเจตนา = เจตนาใหม่ (ทำหน้าที่ YourService.class); startService (เจตนา); ในขณะที่ (! YourService.isConnected) {sleep (300); } หลังจากนั้นวนรอบบริการของคุณกำลังทำงานและคุณสามารถสื่อสารกับมัน .. จากประสบการณ์ของฉันมีข้อ จำกัด บางอย่างในการโต้ตอบกับบริการเช่นนี้
Matt Wolfe

ทำไมมันจึงสามารถเริ่มต้นเฉพาะในActivity.onCreate()?
skywall

มีคำอะไรที่ทำให้คุณไม่ต้องการใช้Intentsโดยการส่งข้อมูลผ่านParcellableข้อความระหว่างกัน?
Aman Alam

2
ใช้งานได้ แต่คำตอบของ @ MaximumGoat นั้นสะอาดกว่าและไม่เกี่ยวข้องกับการรอคอย
Matt

262

ผู้ถามอาจจะย้ายมานานกว่านี้ แต่ในกรณีที่มีคนค้นหาสิ่งนี้ ...

มีวิธีอื่นในการจัดการสิ่งนี้ซึ่งฉันคิดว่าอาจจะง่ายที่สุด

เพิ่มBroadcastReceiverกิจกรรมของคุณ ลงทะเบียนจะได้รับความตั้งใจที่กำหนดเองบางอย่างในและถอนการลงทะเบียนในonResume onPauseจากนั้นส่งความตั้งใจนั้นจากบริการของคุณเมื่อคุณต้องการส่งการอัปเดตสถานะของคุณหรือสิ่งที่คุณมี

ให้แน่ใจว่าคุณจะไม่เป็นไม่มีความสุขถ้าบาง app อื่น ๆ ฟังสำหรับคุณIntent(ทุกคนสามารถทำอะไรที่เป็นอันตราย?) แต่นอกเหนือจากนั้นคุณควรจะเป็นไร

ขอตัวอย่างโค้ดแล้ว:

ในบริการของฉันฉันมีสิ่งนี้:

// Do stuff that alters the content of my local SQLite Database
sendBroadcast(new Intent(RefreshTask.REFRESH_DATA_INTENT));

( RefreshTask.REFRESH_DATA_INTENTเป็นเพียงสตริงคงที่)

ในกิจกรรมการฟังของฉันฉันกำหนดBroadcastReceiver:

private class DataUpdateReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(RefreshTask.REFRESH_DATA_INTENT)) {
          // Do stuff - maybe update my view based on the changed DB contents
        }
    }
}

ฉันประกาศผู้รับของฉันที่ด้านบนของชั้นเรียน:

private DataUpdateReceiver dataUpdateReceiver;

ฉันแทนที่onResumeเพื่อเพิ่มสิ่งนี้:

if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);

และฉันจะแทนที่onPauseเพื่อเพิ่ม:

if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver);

ตอนนี้กิจกรรมของฉันกำลังฟังเพื่อให้บริการของฉันพูดว่า "เฮ้ไปอัพเดทตัวเอง" ฉันสามารถส่งผ่านข้อมูลในIntentแทนที่จะอัปเดตตารางฐานข้อมูลจากนั้นกลับไปค้นหาการเปลี่ยนแปลงภายในกิจกรรมของฉัน แต่เนื่องจากฉันต้องการให้การเปลี่ยนแปลงยังคงมีอยู่ต่อไป


5
อย่างไร? สิ่งที่คุณอธิบายเป็นสิ่งที่ฉันต้องการ แต่ยิ่งไปกว่านั้นฉันต้องการโค้ดตัวอย่างที่สมบูรณ์ ขอบคุณล่วงหน้า. FYI ครั้งสุดท้ายที่ฉันพยายามเขียนวิดเจ็ตส่วนการส่งข้อความใช้เวลา 2 เดือน หัวเราะถ้าคุณต้องการ แต่ผู้เชี่ยวชาญจำเป็นต้องเผยแพร่มากขึ้นเนื่องจาก IMHO Android นั้นซับซ้อนกว่า iOS!

1
aaaaaaa คู่มือ Busy Coder เพื่อการพัฒนา Android ขั้นสูงมีบทที่ยอดเยี่ยมเกี่ยวกับวิดเจ็ต มันเป็นทรัพยากรเพียงอย่างเดียวที่ทำให้ฉันผ่านระเบียบนี้ CommonsWare ผู้เขียนมีชื่อเสียง 115k ใน StackOverflow และฉันขอแนะนำหนังสือเล่มนี้ commonsware.com/AdvAndroid
MaximumGoat

64
Broadcastsเป็นสิ่งที่ยอดเยี่ยมและนอกจากนี้หากคุณไม่ต้องการให้การออกอากาศของคุณไปไกลกว่ากระบวนการของคุณเองให้ลองใช้ a LocalBroadcast: developer.android.com/reference/android/support/v4/content/ …
Cody Caughlan

2
ขอบคุณโคดี้ฉันไม่เคยเห็นมาก่อน
MaximumGoat

3
นี่เป็นวิธีการสื่อสารที่ดีมาก แต่จะทำอย่างไรในกรณีที่ผลลัพธ์ถูกส่งเมื่อกิจกรรมอยู่ในสถานะหยุดชั่วคราว ดังนั้นหลังจากที่กิจกรรม onResume สามารถรอผลลัพธ์ได้นาน และจะไม่มีการรับข้อมูลเพราะข้อมูลพลาด
Anton-M

39

ใช้LocalBroadcastManagerเพื่อลงทะเบียนผู้รับเพื่อฟังการถ่ายทอดที่ส่งจากบริการในท้องถิ่นของคุณภายในแอพอ้างอิงไปที่นี่:

http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html


3
ใช่การสนทนาที่ดีมากเกี่ยวกับลิงค์
SohailAziz

1
LocalBroadcastManagerจะเลิกตอนนี้ในความโปรดปรานของLiveDataหรือเครื่องมือรูปแบบการสังเกตการณ์อื่น ๆ : developer.android.com/reference/androidx/localbroadcastmanager/...
อาลี Nem

20

ฉันประหลาดใจที่ไม่มีใครให้การอ้างอิงถึง Otto event Bus library

http://square.github.io/otto/

ฉันใช้สิ่งนี้ในแอพ android ของฉันและทำงานได้อย่างราบรื่น


7
นอกจากนี้ยังเป็น greenrobot ของEventBusห้องสมุด
Jazzer

15
แต่จำไว้ว่า EventBus และ otto นั้นมักจะอยู่ในขั้นตอนเดียวเสมอ เมื่อคุณใช้บริการที่อยู่ในกระบวนการของตัวเอง (เริ่มต้นด้วยการตั้งค่าandroid:process=":my_service"พวกเขาจะไม่สามารถสื่อสารได้
Ron

20

การใช้ Messenger เป็นอีกวิธีที่ง่ายในการสื่อสารระหว่างบริการและกิจกรรม

ในกิจกรรมสร้างตัวจัดการด้วย Messenger ที่เกี่ยวข้อง นี่จะจัดการข้อความจากบริการของคุณ

class ResponseHandler extends Handler {
    @Override public void handleMessage(Message message) {
            Toast.makeText(this, "message from service",
                    Toast.LENGTH_SHORT).show();
    }
}
Messenger messenger = new Messenger(new ResponseHandler());

Messenger สามารถส่งผ่านไปยังบริการโดยแนบไปกับข้อความ:

Message message = Message.obtain(null, MyService.ADD_RESPONSE_HANDLER);
message.replyTo = messenger;
try {
    myService.send(message);
catch (RemoteException e) {
    e.printStackTrace();
}

ตัวอย่างเต็มรูปแบบสามารถพบได้ในการสาธิต API: MessengerService และ MessengerServiceActivity อ้างถึงตัวอย่างเต็มรูปแบบสำหรับการทำงานของ MyService


1
ชื่นชมมาก! ทำงานได้อย่างสมบูรณ์แบบ เพียงรายละเอียดในรหัส: myService.send(message);ควรจะmessenger.send(message);แทน
Federico Cristina

9

วิธีอื่นที่ไม่ได้กล่าวถึงในความคิดเห็นอื่น ๆ คือการผูกบริการจากกิจกรรมโดยใช้ bindService () และรับอินสแตนซ์ของบริการใน ServiceConnection โทรกลับ ตามที่อธิบายไว้ที่นี่http://developer.android.com/guide/components/bound-services.html


4
นี่เป็นวิธีที่ถูกต้องในการรับการอ้างอิงของอินสแตนซ์ของบริการ
김 준 호

9

นอกจากนี้คุณยังอาจจะใช้งานที่เหมือนLiveDataEventBus

class MyService : LifecycleService() {
    companion object {
        var BUS = MutableLiveData<Object>()
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)

        val testItem : Object

        // expose your data
        if (BUS.hasActiveObservers()) {
            BUS.postValue(testItem)
        }

        return START_NOT_STICKY
    }
}

Activityแล้วเพิ่มผู้สังเกตการณ์จากคุณ

MyService.BUS.observe(this, Observer {
    it?.let {
        // Do what you need to do here
    }
})

คุณสามารถอ่านเพิ่มเติมได้จากบล็อกนี้


2

อีกวิธีหนึ่งคือการใช้ผู้สังเกตการณ์กับคลาสโมเดลปลอมผ่านกิจกรรมและบริการโดยใช้รูปแบบ MVC ที่หลากหลาย ฉันไม่รู้ว่ามันเป็นวิธีที่ดีที่สุดในการบรรลุเป้าหมายนี้หรือไม่ แต่เป็นวิธีที่เหมาะกับฉัน หากคุณต้องการตัวอย่างถามและฉันจะโพสต์บางอย่าง


ฉันกำลังดิ้นรนกับความคิดที่คล้ายกัน ฉันมีกิจกรรมและ 2 บริการที่มีรูปแบบเดียวกัน โมเดลสามารถอัปเดตได้ทั้งในกิจกรรมหรือบริการเหล่านั้นดังนั้นฉันจึงคิดถึงการใช้ Observers แต่ก็ไม่สามารถคิดออกได้ คุณสามารถโพสต์ตัวอย่างเพื่อแสดงความคิดของคุณได้ไหม
pzo

2

วิธีการของฉัน:

ชั้นเรียนเพื่อจัดการส่งและรับข้อความจาก / ถึงบริการ / กิจกรรม:

import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public class MessageManager {

    public interface IOnHandleMessage{
        // Messages
        int MSG_HANDSHAKE = 0x1;

        void onHandleMessage(Message msg);
    }

    private static final String LOGCAT = MessageManager.class.getSimpleName();

    private Messenger mMsgSender;
    private Messenger mMsgReceiver;
    private List<Message> mMessages;

    public MessageManager(IOnHandleMessage callback, IBinder target){
        mMsgReceiver = new Messenger(new MessageHandler(callback, MessageHandler.TYPE_ACTIVITY));
        mMsgSender = new Messenger(target);
        mMessages = new ArrayList<>();
    }

    public MessageManager(IOnHandleMessage callback){
        mMsgReceiver = new Messenger(new MessageHandler(callback, MessageHandler.TYPE_SERVICE));
        mMsgSender = null;
        mMessages = new ArrayList<>();
    }

    /* START Getter & Setter Methods */
    public Messenger getMsgSender() {
        return mMsgSender;
    }

    public void setMsgSender(Messenger sender) {
        this.mMsgSender = sender;
    }

    public Messenger getMsgReceiver() {
        return mMsgReceiver;
    }

    public void setMsgReceiver(Messenger receiver) {
        this.mMsgReceiver = receiver;
    }

    public List<Message> getLastMessages() {
        return mMessages;
    }

    public void addMessage(Message message) {
        this.mMessages.add(message);
    }
    /* END Getter & Setter Methods */

    /* START Public Methods */
    public void sendMessage(int what, int arg1, int arg2, Bundle msgData){
        if(mMsgSender != null && mMsgReceiver != null) {
            try {
                Message msg = Message.obtain(null, what, arg1, arg2);
                msg.replyTo = mMsgReceiver;
                if(msgData != null){
                    msg.setData(msgData);
                }
                mMsgSender.send(msg);
            } catch (RemoteException rE) {
                onException(rE);
            }
        }
    }

    public void sendHandshake(){
        if(mMsgSender != null && mMsgReceiver != null){
            sendMessage(IOnHandleMessage.MSG_HANDSHAKE, 0, 0, null);
        }
    }
    /* END Public Methods */

    /* START Private Methods */
    private void onException(Exception e){
        Log.e(LOGCAT, e.getMessage());
        e.printStackTrace();
    }
    /* END Private Methods */

    /** START Private Classes **/
    private class MessageHandler extends Handler {

        // Types
        final static int TYPE_SERVICE = 0x1;
        final static int TYPE_ACTIVITY = 0x2;

        private IOnHandleMessage mCallback;
        private int mType;

        public MessageHandler(IOnHandleMessage callback, int type){
            mCallback = callback;
            mType = type;
        }

        @Override
        public void handleMessage(Message msg){
            addMessage(msg);
            switch(msg.what){
                case IOnHandleMessage.MSG_HANDSHAKE:
                    switch(mType){
                        case TYPE_SERVICE:
                            setMsgSender(msg.replyTo);
                            sendHandshake();
                            break;
                        case TYPE_ACTIVITY:
                            Log.v(LOGCAT, "HERE");
                            break;
                    }
                    break;
                default:
                    if(mCallback != null){
                        mCallback.onHandleMessage(msg);
                    }
                    break;
            }
        }

    }
    /** END Private Classes **/

}

ในตัวอย่างกิจกรรม:

public class activity extends AppCompatActivity
      implements     ServiceConnection,
                     MessageManager.IOnHandleMessage { 

    [....]

    private MessageManager mMessenger;

    private void initMyMessenger(IBinder iBinder){
        mMessenger = new MessageManager(this, iBinder);
        mMessenger.sendHandshake();
    }

    private void bindToService(){
        Intent intent = new Intent(this, TagScanService.class);
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        /* START THE SERVICE IF NEEDED */
    }

    private void unbindToService(){
    /* UNBIND when you want (onDestroy, after operation...)
        if(mBound) {
            unbindService(mServiceConnection);
            mBound = false;
        }
    }

    /* START Override MessageManager.IOnHandleMessage Methods */
    @Override
    public void onHandleMessage(Message msg) {
        switch(msg.what){
            case Constants.MSG_SYNC_PROGRESS:
                Bundle data = msg.getData();
                String text = data.getString(Constants.KEY_MSG_TEXT);
                setMessageProgress(text);
                break;
            case Constants.MSG_START_SYNC:
                onStartSync();
                break;
            case Constants.MSG_END_SYNC:
                onEndSync(msg.arg1 == Constants.ARG1_SUCCESS);
                mBound = false;
                break;
        }
    }
    /* END Override MessageManager.IOnHandleMessage Methods */

    /** START Override ServiceConnection Methods **/
    private class BLEScanServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            initMyMessenger(iBinder);
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mMessenger = null;
            mBound = false;
        }
    }
    /** END Override ServiceConnection Methods **/

ในตัวอย่างบริการ:

public class Blablabla extends Service
    implements     MessageManager.IOnHandleMessage {

    [...]

    private MessageManager mMessenger;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        super.onBind(intent);
        initMessageManager();
        return mMessenger.getMsgReceiver().getBinder();
    }

    private void initMessageManager(){
        mMessenger = new MessageManager(this);
    }

    /* START Override IOnHandleMessage Methods */
    @Override
    public void onHandleMessage(Message msg) {
    /* Do what you want when u get a message looking the "what" attribute */
    }
    /* END Override IOnHandleMessage Methods */

ส่งข้อความจากกิจกรรม / บริการ:

mMessenger.sendMessage(what, arg1, arg2, dataBundle);

มันทำงานอย่างไร:

ในกิจกรรมที่คุณเริ่มหรือผูกบริการ วิธีการบริการ "OnBind" จะส่งคืน Binder ให้กับ MessageManager ของเขาในกิจกรรมผ่านการใช้วิธีการ "อินเตอร์เฟสการเชื่อมต่อบริการ" อินเตอร์เฟส "OnServiceConnected" คุณจะได้รับ IBinder นี้และเริ่มใช้ MessageManager ของคุณ หลังจากกิจกรรมได้เริ่มต้น MessageManager ของเขา MessageHandler ส่งและจับมือกับบริการเพื่อให้สามารถตั้งค่าผู้ส่ง "MessageHandler" ของเขา ("ส่วนตัว Messenger mMsgSender;" ใน MessageManager) ทำสิ่งนี้บริการรู้ว่าใครส่งข้อความของเขา

คุณยังสามารถใช้สิ่งนี้ได้โดยใช้ List / Queue ของ Messenger "ผู้ส่ง" ใน MessageManager เพื่อให้คุณสามารถส่งข้อความหลายข้อความไปยังกิจกรรม / บริการที่แตกต่างกันหรือคุณสามารถใช้ List / Queue of Messenger "รับ" ใน MessageManager ข้อความจากกิจกรรม / บริการต่างๆ

ในอินสแตนซ์ "MessageManager" คุณมีรายการข้อความทั้งหมดที่ได้รับ

ในขณะที่คุณสามารถเห็นการเชื่อมต่อระหว่าง "กิจกรรมของ Messenger" และ "บริการ Messenger" โดยใช้อินสแตนซ์ "MessageManager" นี้เป็นไปโดยอัตโนมัติมันจะทำผ่านวิธี "OnServiceConnected" และผ่านการใช้ "จับมือกัน"

หวังว่านี่จะเป็นประโยชน์สำหรับคุณ :) ขอบคุณมาก! ลาก่อน: D


2

หากต้องการติดตามคำตอบ @MrSnowflake ด้วยตัวอย่างโค้ด นี่คือ Xabber ตอนนี้มาเปิดApplicationชั้นเรียน Applicationชั้นศูนย์กลางและประสานงานListenersและ ManagerInterfaces และอื่น ๆ ผู้จัดการทุกประเภทถูกโหลดแบบไดนามิก Activity´sเริ่มต้นใน Xabber จะรายงานในประเภทของListenerพวกเขา และเมื่อServiceเริ่มต้นก็จะรายงานไปยังApplicationชั้นเรียนเป็นเริ่มต้น ตอนนี้การส่งข้อความไปยังActivityสิ่งที่คุณต้องทำคือทำให้คุณActivityกลายเป็นคนlistenerที่คุณต้องการ ในการOnStart() OnPause()ลงทะเบียน / unreg ServiceสามารถขอApplicationชั้นเพียงแค่ว่าlistenerมันจำเป็นที่จะต้องพูดไปและถ้ามันมีแล้วกิจกรรมที่มีความพร้อมที่จะได้รับ

เมื่อผ่านApplicationชั้นเรียนคุณจะเห็นว่ามีการปล้นสะดมมากกว่านี้


ลิงก์ที่ให้ไว้ส่งผลให้ GitHub 404 มันย้ายไปหรือเปล่า
JE Carter II

ใช่ดูเหมือนว่าจะทำงานตอนนี้ ต้องเป็นปัญหาชั่วคราวใน GitHub
JE Carter II

1

การผูกเป็นอีกวิธีหนึ่งในการสื่อสาร

สร้างการติดต่อกลับ

public interface MyCallBack{

   public void getResult(String result);

}

ด้านกิจกรรม:

  1. ใช้อินเทอร์เฟซในกิจกรรม

  2. จัดเตรียมการนำไปใช้สำหรับวิธี

  3. ผูกกิจกรรมกับบริการ

  4. ลงทะเบียนและยกเลิกการลงทะเบียนการโทรกลับเมื่อบริการถูกผูกมัดและไม่ถูกผูกไว้กับกิจกรรม

    public class YourActivity extends AppCompatActivity implements MyCallBack{
    
          private Intent notifyMeIntent;
          private GPSService gpsService;
          private boolean bound = false;
    
          @Override
          public void onCreate(Bundle sis){
    
              // activity code ...
    
              startGPSService();
    
          }
    
          @Override
          public void getResult(String result){
           // show in textView textView.setText(result);
          }
    
          @Override
          protected void onStart()
          {
              super.onStart();
              bindService();
          }
    
          @Override
          protected void onStop() {
              super.onStop();
              unbindService();
          }
    
          private ServiceConnection serviceConnection = new ServiceConnection() {
    
                @Override
                public void onServiceConnected(ComponentName className, IBinder service) {
    
                      GPSService.GPSBinder binder = (GPSService.GPSBinder) service;
                      gpsService= binder.getService();
                      bound = true;
                      gpsService.registerCallBack(YourActivity.this); // register
    
               }
    
               @Override
               public void onServiceDisconnected(ComponentName arg0) {
                      bound = false;
               }
          };
    
          private void bindService() {
    
               bindService(notifyMeIntent, serviceConnection, Context.BIND_AUTO_CREATE);
          }
    
          private void unbindService(){
               if (bound) {
                     gpsService.registerCallBack(null); // unregister            
                     unbindService(serviceConnection);
                     bound = false;
                }
          }
    
          // Call this method somewhere to start Your GPSService
          private void startGPSService(){
               notifyMeIntent = new Intent(this, GPSService.class);
               startService(myIntent );
          }
    
     }

บริการด้าน:

  1. เริ่มต้นการโทรกลับ

  2. เรียกใช้เมธอด callback เมื่อต้องการ

     public class GPSService extends Service{
    
         private MyCallBack myCallback;
         private IBinder serviceBinder = new GPSBinder();
    
         public void registerCallBack(MyCallBack myCallback){
              this.myCallback= myCallback;
         }
    
         public class GPSBinder extends Binder{
    
             public GPSService getService(){
                  return GPSService.this;
             }
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent){
             return serviceBinder;
        }
     }

คุณจะออกจากserviceConnection onCreateโปรดแก้ไข
Adeel Zafar

ไม่จำเป็นต้องอยู่ข้างในสร้าง
Rohit Singh เมื่อ

0

ดังกล่าวโดย Madhur คุณสามารถใช้รถบัสเพื่อการสื่อสาร

ในกรณีที่ใช้ Bus คุณมีตัวเลือกดังนี้

อ็อตโตเหตุการณ์ไลบรารีบัส (คัดค้าน RxJava)

http://square.github.io/otto/

EventBus ของ Green Robot

http://greenrobot.org/eventbus/

NYBus (RxBus ดำเนินการโดยใช้ RxJava คล้ายกับ EventBus)

https://github.com/MindorksOpenSource/NYBus


0

นอกจาก LocalBroadcastManager, Event Bus และ Messengerตอบแล้วในคำถามนี้เราสามารถใช้Intent ที่รอดำเนินการเพื่อสื่อสารจากบริการ

ดังที่กล่าวไว้ในโพสต์บล็อกของฉัน

การสื่อสารระหว่างบริการและกิจกรรมสามารถทำได้โดยใช้ PendingIntent เพื่อให้เราสามารถใช้ createPendingResult () .createPendingResult () สร้างวัตถุ PendingIntent ใหม่ซึ่งคุณสามารถมอบบริการเพื่อใช้และส่งข้อมูลผลลัพธ์กลับไปยังกิจกรรมของคุณภายใน onActivityResult (int, โทรกลับ int, Intent) เนื่องจาก PendingIntent เป็น Parcelable และสามารถใส่เข้าไปใน Intent Extra ได้กิจกรรมของคุณสามารถส่ง PendingIntent นี้ไปยังบริการได้ในทางกลับกันสามารถเรียกใช้ send () เมธอด PendingIntent เพื่อแจ้งให้ทราบ กิจกรรมผ่าน onActivityResult ของเหตุการณ์

กิจกรรม

public class PendingIntentActivity extends AppCompatActivity
{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

PendingIntent pendingResult = createPendingResult(
100, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), PendingIntentService.class);
intent.putExtra("pendingIntent", pendingResult);
startService(intent);

}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 100 && resultCode==200) {
Toast.makeText(this,data.getStringExtra("name"),Toast.LENGTH_LONG).show();
}
super.onActivityResult(requestCode, resultCode, data);
}
}

บริการ

public class PendingIntentService extends Service {

    private static final String[] items= { "lorem", "ipsum", "dolor",
            "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi",
            "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam",
            "vel", "erat", "placerat", "ante", "porttitor", "sodales",
            "pellentesque", "augue", "purus" };
    private PendingIntent data;

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        data = intent.getParcelableExtra("pendingIntent");

        new LoadWordsThread().start();
        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

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

    class LoadWordsThread extends Thread {
        @Override
        public void run() {
            for (String item : items) {
                if (!isInterrupted()) {

                    Intent result = new Intent();
                    result.putExtra("name", item);
                    try {
                        data.send(PendingIntentService.this,200,result);
                    } catch (PendingIntent.CanceledException e) {

                        e.printStackTrace();
                    }
                    SystemClock.sleep(400);

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