Android 更新后台运行的服务

Android 更新后台运行的服务,android,android-intent,android-service,android-broadcast,Android,Android Intent,Android Service,Android Broadcast,我需要执行这样一个程序: 启动后台服务 使用参数更新服务(从UI-用户输入) 活动结束后,服务应继续运行,并每分钟向HTTP服务器发出请求。在这个阶段中,我仍然需要在第二阶段中更新的参数——我将它们发送到服务器 该服务应该存储服务器的最后一个响应,并用最后一个响应对每个响应进行压缩。如果有更改,请通知用户 最后,当活动再次启动时,服务应使用最新的服务器响应更新UI 我尝试的是: BroadcastReceiver-问题在于OnReceive结束了所有未声明为final的参数后,将清除这些参数,而

我需要执行这样一个程序:

  • 启动后台服务
  • 使用参数更新服务(从UI-用户输入)
  • 活动结束后,服务应继续运行,并每分钟向HTTP服务器发出请求。在这个阶段中,我仍然需要在第二阶段中更新的参数——我将它们发送到服务器
  • 该服务应该存储服务器的最后一个响应,并用最后一个响应对每个响应进行压缩。如果有更改,请通知用户
  • 最后,当活动再次启动时,服务应使用最新的服务器响应更新UI
  • 我尝试的是: BroadcastReceiver-问题在于OnReceive结束了所有未声明为final的参数后,将清除这些参数,而且我没有找到一种方法来更新每分钟自动发送的意图

    服务-使用startService()-问题是当活动结束服务(如停止和启动)时,刷新了它的所有参数。再一次,我没有弄明白如何在服务启动后更新参数

    那么如何处理这种情况呢


    谢谢。

    听起来您需要做的是能够“绑定”到您的服务。我在下面发布了一个简单的模板,说明了如何做到这一点。出于您的目的,您需要在服务类中存储变量并创建getter,以便在重新启动活动时可以获得最新的变量。另外-请注意,我在onResume和onPause中启动和停止下面的服务示例。毫无疑问,你会想用不同的方式来做这件事

    //Activity
    
    //Bind to Service Example
    
    public class ExampleActivity extends Activity implements OnClickListener {
    
    // UI
    private Button binderButton;
    
    // service
    private MyService myService;
    private Intent serviceIntent;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_layout);
    
        // binder button
        binderButton = (Button) findViewById(R.id.button1);
        binderButton.setOnClickListener(this);
        binderButton.setText("start");
    
        serviceIntent = new Intent(this, MyService.class);
    }
    
    private ServiceConnection serviceConnection = new ServiceConnection() {
    
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myService = ((MyService.MyBinder) service).getService();
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            myService = null;
        }
    };
    
    @Override
    protected void onResume() {
        super.onResume();
        // start the service
        startService(serviceIntent);
        // bind to the service
        bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
    }
    
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.button1:
            // call method within the service
            myService.doServiceStuff();
            break;
        }
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        stopService(serviceIntent);
        unbindService(serviceConnection);
    }
    }
    

    //服务
    公共类MyService扩展服务{
    专用最终IBinder活页夹=新的MyBinder();
    @凌驾
    公共IBinder onBind(意图arg0){
    返回活页夹;
    }
    公共无效doServiceStuff(){
    task.execute();
    }
    //创建一个内部活页夹类
    公共类MyBinder扩展了Binder{
    公共MyService getService(){
    返回MyService.this;
    }
    }
    AsyncTask任务=新建AsyncTask(){
    @凌驾
    受保护的Void doInBackground(Void…参数){
    Log.d(“yourTag”,“长时间运行的服务任务”);
    返回null;
    }       
    };
    }
    
    谢谢javaJoe,虽然你的回答没有解决我的问题,但给了我一些好主意

    我所做的:

  • 在活动onCreate中,检查我的服务是否正在运行,如果正在运行,则绑定它,否则,创建新服务并绑定它

  • 使用setter和getter在服务和活动之间传输参数

  • 在ActivityOnDestroy中(问题是服务调用self-Destory),Activity通过Intent将最终参数发送给BroadcastReceiver。BroadcastReceiver随后再次启动服务,并使用正确的参数启动服务

  • 我不知道这个架构是否理想,我想得到一些反馈

    代码如下:

    活动:

        @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        //Set Service Intent
        serviceIntent = new Intent(this, UpdateService.class);
        if (isMyServiceRunning()) {
            //Bind to the service
            bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
        }else{
            updateService=new UpdateService();
            //Start the service
            startService(serviceIntent);
            //Bind to the service
            bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
        }
    }
    
    private boolean isMyServiceRunning() {
        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (UpdateService.class.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }
    
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            updateService = ((UpdateService.MyBinder) service).getService();
            //Set Initial Args
            updateService.setParams(int arg0);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            updateService = null;
        }
    };
    
    @Override
    protected void onDestroy() {
        //UnBind from service
        unbindService(serviceConnection);
        //Stop Service
        stopService(serviceIntent);
        //Prepare intent to broadcast reciver
        Intent intent = new Intent(MainActivity.this,ServiceRunnerBCR.class);
        intent.setAction(ServiceRunnerBCR.ACTION_SET_UpdateService);
        intent.putExtra(ServiceRunnerBCR.keyVal_arg0, arg0);
        intent.putExtra(ServiceRunnerBCR.keyVal_arg1, arg1);
        //Send broadcast to start UpdateService after the activity ended
        sendBroadcast(intent);
    
        super.onStop();
    }
    
    广播接收器:

    public class ServiceRunnerBCR extends BroadcastReceiver {
    
    
        public static final String ACTION_SET_UpdateService = "ACTION_ALARM";
    
        public static final String keyVal_arg0="ARG0";
        public static final String keyVal_arg1="ARG1";
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(ACTION_SET_UpdateService)){   
                 updateIntent(context, intent.getDoubleExtra(keyVal_arg0, 0.02), intent.getStringExtra(keyVal_arg1));
            }
        }
    
        private void updateIntent(Context context, double arg0, String arg1){
            Intent intent = new Intent(context,UpdateService.class);
            intent.setAction(ACTION_SET_UpdateService);
            intent.putExtra(keyVal_arg0, arg0);
            intent.putExtra(keyVal_arg1, arg1);
            synchronized (this){
                try {
                    this.wait(6000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            context.startService(intent);
            Log.d("OREN","ServiceRunner");
        }
    }
    
    服务:

    public class UpdateService extends Service {
    
        private final IBinder binder = new MyBinder();
        public static final String keyVal_arg0="ARG0";
            public static final String keyVal_arg1="ARG1";
        private Timer timer;
        private HTTPHandler http = new HTTPHandler();
        private int test=0;
        double arg0=0;
        String arg1= "";
    
        private TimerTask updateTask = new TimerTask() {
            @Override
            public void run() {
                test++;
                Log.d("OREN", "Timer task doing work " + test + " arg0: " + arg0);
                            //Do some work here
            }
        };
    
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            if (intent!=null){
                arg0=intent.getDoubleExtra(keyVal_arg0, 0.002);
                            arg1=intent.getStringExtra(keyVal_arg1);
                timer = new Timer("UpdateTimer");
                timer.schedule(updateTask, 1000L, 10 * 1000L);
                Log.d("OREN", "ServiceStarted" + test);
            }
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            Log.d("OREN", "OnBind" + test);
            return binder;
        }
    
        public void setArg0(double d){
            arg0=d;
        }
    
        // create an inner Binder class
        public class MyBinder extends Binder {
            public UpdateService getService() {
                return UpdateService.this;
            }
        }
    
        @Override
        public void onDestroy() {
            Log.d("OREN", "OnDestroy" + test);
            super.onDestroy();
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            Log.d("OREN", "OnUnBind" + test);
            return super.onUnbind(intent);
        }
    }
    

    这可能会有所帮助-谢谢,但不幸的是,解除绑定后服务计时器任务仍然停止。顺便说一句,可能是计时器任务的问题:
    code
    private TimerTask updateTask=new TimerTask(){@Override public void run(){test++;Log.d(“OREN”,“timer task doing work”+test);};public void runOnTimer(double rad){radius=rad;timer=new timer(“UpdateTimer”);timer.schedule(updateTask,1000L,10*1000L);}
    code
    尝试改用重复的AlarmManager。它将通过挂起的意图向操作系统注册,因此您可以确保它不会停止,除非您明确告诉它。在不知道正在解决的具体问题的情况下,我无法确定这是否是最好的方法。不过,我可以说几句话。1) 您正在从onDestroy()中调用super.onStop()。这无疑最终会产生问题。2) ,您正在UI线程上调用sleep(6000)。您也正在对其进行同步,这是不必要的。如果需要某种延迟,最好在那里使用处理程序。然而,硬编码延迟可能表明您的体系结构需要更改。我建议尽量避免这种情况。:)谢谢,我将等待(6000)更改为while(isMyServiceRunning())。如果我在onStop事件而不是onDestroy事件中停止服务,它不会引起问题吗?我认为将其保留在onDestroy中是可以的。问题是您正在重写onDestroy,但随后调用onStop()。例如,它应该是“public void ondestory(){super.ondestory();}”。您有“public void onDestroy(){super.onStop();}”。而且,听起来您仍然在用“while{(isMyServiceRunning())}”阻塞主UI线程。
    public class UpdateService extends Service {
    
        private final IBinder binder = new MyBinder();
        public static final String keyVal_arg0="ARG0";
            public static final String keyVal_arg1="ARG1";
        private Timer timer;
        private HTTPHandler http = new HTTPHandler();
        private int test=0;
        double arg0=0;
        String arg1= "";
    
        private TimerTask updateTask = new TimerTask() {
            @Override
            public void run() {
                test++;
                Log.d("OREN", "Timer task doing work " + test + " arg0: " + arg0);
                            //Do some work here
            }
        };
    
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            if (intent!=null){
                arg0=intent.getDoubleExtra(keyVal_arg0, 0.002);
                            arg1=intent.getStringExtra(keyVal_arg1);
                timer = new Timer("UpdateTimer");
                timer.schedule(updateTask, 1000L, 10 * 1000L);
                Log.d("OREN", "ServiceStarted" + test);
            }
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            Log.d("OREN", "OnBind" + test);
            return binder;
        }
    
        public void setArg0(double d){
            arg0=d;
        }
    
        // create an inner Binder class
        public class MyBinder extends Binder {
            public UpdateService getService() {
                return UpdateService.this;
            }
        }
    
        @Override
        public void onDestroy() {
            Log.d("OREN", "OnDestroy" + test);
            super.onDestroy();
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            Log.d("OREN", "OnUnBind" + test);
            return super.onUnbind(intent);
        }
    }