搜尋

首頁  >  問答  >  主體

长连接 - android 如何取得正在运行的service对象

在写有关推送的代码,用的长连接的方式。
具体逻辑:登录时 启service,service中启一个线程,线程中构建一个CommunicateManegr对象,此对象里面有一个BlockingDeque双端队列处理包的顺序问题, 还有若干线程分别处理心跳包、登录包、推送消息、其它业务消息、断线重连、心跳检测等操作。

初次运行程序,长连接建立起来;然后退出系统,为了保持长连接,后台服务仍运行。再次运行程序时,需要判断后台服务是否仍在运行,仍在运行的话,需要取出之前运行的service对象,添加一些登录包。

这里的取出之前运行的service对象,如何取出?

不局限与取出之前运行的service对象的问题,是否从一开始 我关于长连接的处理逻辑就有一些理解不当的地方?

伪代码:

class MyService extends Service{

    public CommnicateManager cManager;
    @Override
    public void onCreate() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                CommunicateManager manager = CommunicateManager.getInstance();
                cManager = manager;
                manager.connect();
                manager.add(LoginPackage);//添加登录包
                manager.add(registerPackage);//添加注册包
                manager.startHeardBeatThread();//开启心跳线程
                manager.startCommunicate();//开启其它线程
            }
        }.start();
    }
}

public class LoginActivtiy extends BaseActivity implements OnClickListener {
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.login:
                if (isServiceWork(LoginActivtiy.this,"com.example.service")){//判断第一次运行的服务是否存在
                    //TODO: 需要得到第一次运行的服务对象service  如何得到???       manager.add(loginPackage)
                    
                }else{
                    startService(myService);
                }
            break;
            default:
            break;
        }
    }
    
    
    //判断某个服务是否正在运行的方法
    public boolean isServiceWork(Context mContext, String serviceName) {
        boolean isWork = false;
        ActivityManager myAM = (ActivityManager) mContext
                .getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningServiceInfo> myList = myAM.getRunningServices(200);
        // List<RunningAppProcessInfo> apps = myAM.getRunningAppProcesses();

        if (myList.size() <= 0) {
            return false;
        }

        for (int i = 0; i < myList.size(); i++) {
            String mName = myList.get(i).service.getClassName().toString();
            if (mName.equals(serviceName)) {
                isWork = true;
                break;
            }
        }

        return isWork;
    }
}
巴扎黑巴扎黑2773 天前695

全部回覆(3)我來回復

  • 阿神

    阿神2017-04-17 16:29:03

    既然是想要長連接,就要service常駐後台,因此,bindService方式是不可行的。你需要一個remote service,使用startService方式,把心跳服務獨立於應用之外,至於應用和remote service之間的通信,可有兩種方式,Broadcast和IPC。

    • Broadcast,讓你的remote service不斷的向外發送廣播,應用接收廣播並更新心跳數據(假設需要更新的數據是這個),缺點就是廣播是低效且不穩定,易受系統監控影響,有可能遺失某一些時刻的廣播數據,不過簡單,容易實現,對數據不嚴格要求可以考慮使用這個方式;Broadcast,让你的remote service不断的向外发送广播,应用接收广播并更新心跳数据(假设需要更新的数据是这个),缺点就是广播是低效且不稳定,易受系统监控影响,有可能丢失某一些时刻的广播数据,不过简单,容易实现,对数据不严格要求可以考虑使用这个方式;

    • IPC

    IPC,即AIDL方式,如果你對AIDL熟悉,強烈建議你使用這個來實現與remote service的通信,如果不熟悉,會有一定難度,不過就當學習吧,屬於Android高階知識,後來也是會有很大幫助的。

    🎜 🎜至於你想取得Service對象,確實不太準確,並沒有service本身的API能告知使用者service對像是否存在。可以換個思路,在前面開啟remote service的前提下,可以使用ActivityManager來查詢應用進程,匹配remote service進程名,進程名存在,則remote service存在。大體上只提供了一些思路,具體實作還需要你去找資料完善了。 🎜

    回覆
    0
  • 怪我咯

    怪我咯2017-04-17 16:29:03

    bindservice

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 16:29:03

    Service的啟動方式,除了StartService還有BindService。

    這樣啟動Service。

     bindService(Intent service, ServiceConnection conn,int flags);

    這是一個conn物件。

    private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
               //TODO 这里就得到了service对象
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        };

    當然你還要在Service裡面複寫Onbind,這個方法會回傳一個Ibinder對象,裡麵包含著Service對象。

    回覆
    0
  • 取消回覆