简体   繁体   English

无限循环android中的服务

[英]service in infinite loop android

I want to call a service which repeatedly queries a Parse.com database and monitors a specific attribute.Here's what Ive got so far: 我想调用一个服务,该服务反复查询Parse.com数据库并监视特定属性。这是到目前为止我得到的:

public class Battle extends Service {
@Override
public int onStartCommand(Intent intent,int flags,int startId)
{ 
    Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
     ParseUser currentUser = ParseUser.getCurrentUser();
     username = currentUser.getString("username");
    findinBackground();

     return START_STICKY;
}




private void findinBackground(){
//public void run() {
    // TODO Auto-generated method stub
    while(true)
    {
    query = ParseUser.getQuery();
     query.whereEqualTo("isAttacking", username);
     query.findInBackground(new FindCallback<ParseUser>() {
          public void done(List<ParseUser> objects, ParseException e) {
              if ((e == null)&(objects.size() != 0))
            {
                // The query was successful.

                    ParseUser attacker = objects.get(0);
                    String attackerName = attacker.getUsername();
                    Log.i("ambustest",attackerName);
                    makeToast(attackerName);

            } 
              else
              {
                Log.i("fd","Something went wrong.");
            }  
          }
        });
    }
}

}

This code compiles fine but stops responding at runtime.Here's my logcat: 这段代码可以正常编译,但是在运行时停止响应。这是我的日志: logcat的

You need to call the service on a separate thread 您需要在单独的线程上调用服务

@Override
public int onStartCommand(Intent intent,int flags,int startId)
{ 
    Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
    ParseUser currentUser = ParseUser.getCurrentUser();
    username = currentUser.getString("username");
    new Thread()
    {
        public void run() {
            findinBackground();
        }
    }.start();

 return START_STICKY;
}

It should be noted that Intent Service is automatically called on a separate thread, however a regular service is not. 应该注意的是,Intent Service是在单独的线程上自动调用的,但是常规服务却不是。

Services are run on the same thread as your UI. 服务与UI在同一线程上运行。 If you want to do time consuming operations, you need to fire them off in a separate thread. 如果要执行耗时的操作,则需要在单独的线程中将其触发。

The best solution is a Remote Service with a Handler that reports your client(s) (Activity) about changes. 最好的解决方案是带有处理程序的远程服务,该处理程序向您的客户(活动)报告更改。

http://developer.android.com/reference/android/app/Service.html http://developer.android.com/reference/android/app/Service.html

Your Service will run in a seperate process 您的服务将在单独的过程中运行

First you need a AIDL - as an interface to communicate with service and client 首先,您需要一个AIDL-作为与服务和客户端进行通信的界面

// IRemoteService.aidl
package de.contecon.android.util.abstractservice;
interface IRemoteService {
   void registerCallback(IRemoteServiceCallback mCallback);
   void unregisterCallback(IRemoteServiceCallback mCallback);
}

Your Service can look like this 您的服务可能如下所示

//RemoteService.java
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        return START_STICKY_COMPATIBILITY;
    }

    @Override
    public void onCreate() {
        // While this service is running, it will continually increment a
        // number.  Send the first message that is used to perform the
        // increment.
        mHandler.sendEmptyMessage(REPORT_MSG);
    }

@Override
    public IBinder onBind(Intent intent) {
        // Select the interface to return.  If your service only implements
        // a single interface, you can just return it here without checking
        // the Intent.
        if (IRemoteService.class.getName().equals(intent.getAction())) {
            return mBinder;
        }
//Example for a second Binder
       // if (IRemoteServiceSecondary.class.getName().equals(intent.getAction())) {
       //     return mBinderSec;
       // }
        return null;
    }
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
        @Override
        public void registerCallback(IRemoteServiceCallback mCallback) throws RemoteException {
            if (mCallback != null) mCallbacks.register(mCallback);
        }
        @Override
        public void unregisterCallback(IRemoteServiceCallback mCallback) throws RemoteException {
            if (mCallback != null) mCallbacks.unregister(mCallback);
        }
    };
/**
     * Our Handler used to execute operations on the main thread.  This is used
     * to schedule increments of our value.
     */
    private final Handler mHandler = new Handler() {
        @Override public void handleMessage(Message msg) {
            switch (msg.what) {
                // It is time to bump the value!
                case REPORT_MSG: {
                    // Up it goes.
                    int value = ++mValue;
                    // Broadcast to all clients the new value.
                    final int N = mCallbacks.beginBroadcast();
                    for (int i=0; i<N; i++) {
                        try {
                            mCallbacks.getBroadcastItem(i).valueChanged(value);
                        } catch (RemoteException e) {
                            // The RemoteCallbackList will take care of removing
                            // the dead object for us.
                        }
                    }
                    mCallbacks.finishBroadcast();
                    // Repeat every 1 second.
                    sendMessageDelayed(obtainMessage(REPORT_MSG), 1*1000);
                } break;
                default:
                    super.handleMessage(msg);
            }
        }
    };

And your Client 还有你的客户

 /**
     * This implementation is used to receive callbacks from the remote
     * service.
     */
    private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
        /**
         * This is called by the remote service regularly to tell us about
         * new values.  Note that IPC calls are dispatched through a thread
         * pool running in each process, so the code executing here will
         * NOT be running in our main thread like most other things -- so,
         * to update the UI, we need to use a Handler to hop over there.
         */
        public void valueChanged(int value) {
            mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));
        }
    };
    private static final int BUMP_MSG = 1;
    private Handler mHandler = new Handler() {
        @Override public void handleMessage(Message msg) {
            switch (msg.what) {
                case BUMP_MSG:
                    mCallbackText.setText("Received from service: " + msg.arg1);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };

public void startService() {
        // Make sure the service is started.  It will continue running
        // until someone calls stopService().
        // We use an action code here, instead of explictly supplying
        // the component name, so that other packages can replace
        // the service.
        startService(new Intent(
                "your.action.uri.code.REMOTE_SERVICE"));

    }

    public void stopService() {
        // Cancel a previous call to startService().  Note that the
        // service will not actually stop at this point if there are
        // still bound clients.
        stopService(new Intent(
                "your.action.uri.code.REMOTE_SERVICE"));
    }

 /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the service object we can use to
            // interact with the service.  We are communicating with our
            // service through an IDL interface, so get a client-side
            // representation of that from the raw service object.
            mService = IRemoteService.Stub.asInterface(service);
            mCallbackText.setText("Attached.");
            // We want to monitor the service for as long as we are
            // connected to it.
            try {
                mService.registerCallback(mCallback);
            } catch (RemoteException e) {
                // In this case the service has crashed before we could even
                // do anything with it; we can count on soon being
                // disconnected (and then reconnected if it can be restarted)
                // so there is no need to do anything here.
            }
            // As part of the sample, tell the user what happened.
            Toast.makeText(RemoteServiceBinding.this, "service connected",
                    Toast.LENGTH_SHORT).show();
        }
        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mCallbackText.setText("Disconnected.");
            // As part of the sample, tell the user what happened.
            Toast.makeText(RemoteServiceBinding.this,"service disconnected",
                    Toast.LENGTH_SHORT).show();
        }
    };

private void bindService(){
        // Establish a couple connections with the service, binding
        // by interface names.  This allows other applications to be
        // installed that replace the remote service by implementing
        // the same interface.
        bindService(new Intent(IRemoteService.class.getName()),
                mConnection, Context.BIND_AUTO_CREATE);
        bindService(new Intent(IRemoteServiceSecondary.class.getName()),
                mSecondaryConnection, Context.BIND_AUTO_CREATE);
        mIsBound = true;
        mCallbackText.setText("RemoteServiceBinding.");
    }

    private void unbindService(){
        if (mIsBound) {
            // If we have received the service, and hence registered with
            // it, then now is the time to unregister.
            if (mService != null) {
                try {
                    mService.unregisterCallback(mCallback);
                } catch (RemoteException e) {
                    // There is nothing special we need to do if the service
                    // has crashed.
                }
            }
            // Detach our existing connection.
            unbindService(mConnection);
            unbindService(mSecondaryConnection);
            mIsBound = false;
            mCallbackText.setText("Unbinding.");
        }
    }

AndroidManifest.xml AndroidManifest.xml

<service
            android:name=".service.RemoteService"
            android:process=":remote"
            android:enabled="true" >
            <intent-filter>
                <!-- These are the interfaces supported by the service, which
                     you can bind to. -->
                <action android:name="de.your.path.util.abstractservice.IRemoteService" />

                <!-- This is an action code you can use to select the service
                     without explicitly supplying the implementation class. -->
                <action android:name="your.action.uri.code.REMOTE_SERVICE" />
            </intent-filter>
        </service>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM