搜索

首页  >  问答  >  正文

长连接 - 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 天前694

全部回复(3)我来回复

  • 阿神

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

    既然是想要长连接,就要service常驻后台,因此,bindService方式是不可行的。你需要一个remote service,使用startService方式,把心跳服务独立于应用之外,至于应用和remote service之间的通信,可有两种方式,Broadcast和IPC。

    • Broadcast,让你的remote service不断的向外发送广播,应用接收广播并更新心跳数据(假设需要更新的数据是这个),缺点就是广播是低效且不稳定,易受系统监控影响,有可能丢失某一些时刻的广播数据,不过简单,容易实现,对数据不严格要求可以考虑使用这个方式;

    • 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
  • 取消回复