在无限循环android中服务

时间:2013-11-11 21:40:52

标签: android android-service parse-platform

我想调用一个反复查询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.");
            }  
          }
        });
    }
}

}

此代码编译正常,但在运行时停止响应。这是我的logcat: Logcat

3 个答案:

答案 0 :(得分:1)

您需要在单独的线程上调用服务

@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;
}

应该注意的是,Intent Service会在一个单独的线程上自动调用,但常规服务不是。

答案 1 :(得分:0)

服务与UI在同一个线程上运行。如果您想进行耗时的操作,则需要在单独的线程中关闭它们。

答案 2 :(得分:0)

最佳解决方案是具有处理程序的远程服务,该处理程序会报告您的客户(活动)有关更改的信息。

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

您的服务将在单独的过程中运行

首先,您需要一个AIDL - 作为与服务和客户端进行通信的接口

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

您的服务可能如下所示

//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);
            }
        }
    };

和您的客户

 /**
     * 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

<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>