Android 在onCreate()方法中将消息发送到未绑定的服务

Android 在onCreate()方法中将消息发送到未绑定的服务,android,service,callback,ipc,oncreate,Android,Service,Callback,Ipc,Oncreate,我正在开发一个应用程序,我需要在离开应用程序时(onPause())向服务发送一条消息,使用一个包来保存我的应用程序的一些数据。它工作得很好。我的问题是,当应用程序启动时,它执行onCreate()方法,在该方法中,我使用以下代码在应用程序和服务之间建立连接: MyActivity.java // This takes care of make the connection this.getApplicationContext().startService(intent); this.bindS

我正在开发一个应用程序,我需要在离开应用程序时(onPause())向服务发送一条消息,使用一个包来保存我的应用程序的一些数据。它工作得很好。我的问题是,当应用程序启动时,它执行onCreate()方法,在该方法中,我使用以下代码在应用程序和服务之间建立连接:

MyActivity.java

// This takes care of make the connection
this.getApplicationContext().startService(intent);
this.bindService(intent, mConnectionCallback, Context.BIND_AUTO_CREATE);
/** I need restore the bundle that is in the service, thus i'm sending a message */
Message msg = Message.obtain();
try {
    Bundle bundle = new Bundle();
    msg.setData(bundle);
    msg.what = MyService.REQUEST_BUNDLE;
    msg.replyTo = mMessageDispatcher;
    mServiceConnection.send(msg);
} catch (RemoteException e) {
    e.printStackTrace();
}
问题是,当您发送消息时,连接仍然不会建立,因此这将引发NullPointerException。我不知道该如何处理这件事。很明显,我的应用程序只是一个简单的时间跟踪器,当用户退出应用程序时,我希望将时间保存在服务包中。有没有一种方法可以在建立连接后立即发送消息

有些人会说:-“在回调ServiceConnection的方法onServiceConnected(ComponentName类名称,IBinder服务)中建立连接后发送消息”。但问题是我已经将活动与服务的API实现分离了。以下是我的课程的完整代码:

ServiceManager.java

public class ServiceManager extends Service {
private NotificationManager mNM;

protected HashMap<Integer, Method> magicSwitch = new HashMap<Integer, Method>();

public ServiceManager() {
    try {
        for (Method method : Class
                .forName(getClass().getCanonicalName())
                .getMethods()) {
            if (method.isAnnotationPresent(ExecutesWhen.class)) {
                try {
                        ExecutesWhen a = method.getAnnotation(ExecutesWhen.class);
                        magicSwitch.put(a.what(), method);
                        Log.d("AkrasiaService","AkrasiaService now knows how handle a "+method.getName()+" with id="+a.what());
                } catch (Throwable ex) {
                    ex.printStackTrace();
                }
            }
        }
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

class ServiceHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        Log.d("AkrasiaService","The service is going to manage a message from the client with what="+msg.what);
        try {
            Method met = magicSwitch.get(msg.what);
            if (met == null) {
                throw new NonExistingWhatException();
            } else {
                met.invoke(ServiceManager.this, msg);
            }
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

/**
 * Target we publish for clients to send messages to IncomingHandler.
 */
final Messenger mMessageInBox = new Messenger(new ServiceHandler());

/**
 * Sends a message to the replyTo client.
 * @param replyTo: The <code>Messenger</code> to reply the message.
 * @param what: The what (subject).
 * @param bundle: A data bundle that will go attached to the message.
 */
protected void sendMessageToClient(Messenger replyTo, int what, Bundle bundle) {
    try {
        Message msg = Message.obtain(null,
                what, 0, 0);
        msg.setData(bundle);
        replyTo.send(msg);
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

@Override
public IBinder onBind(Intent intent) {
    return mMessageInBox.getBinder();
}

@Override
public void onCreate() {
    mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
    showNotification();
}

/**
 * Show a notification while this service is running.
 */
private void showNotification() {
    //Here we immplement the notification
}
}

AkrasiaService.java(我的具体服务)

}

java

public class AnnotatedHandler extends Handler {

protected HashMap<Integer, Method> magicSwitch = new HashMap<Integer, Method>();

public AnnotatedHandler() {
    try {
        for (Method method : this.getClass().getMethods() ) {
            if (method.isAnnotationPresent(ExecutesWhen.class)) {
                try {
                    ExecutesWhen a = method
                            .getAnnotation(ExecutesWhen.class);
                    magicSwitch.put(a.what(), method);
                    Log.d("AnnotatedHandler","AnnotatedHandler now knows how handle a "+method.getName()+" and id"+a.what());
                } catch (Throwable ex) {
                    ex.printStackTrace();
                }
            }
        }
    } catch (SecurityException e) {
        e.printStackTrace();
    }
}

@Override
public void handleMessage(Message msg) {
    try {
        Log.d("AnnotatedHandler","The service is going to manage a message from the client with what="+msg.what);
        Method met = magicSwitch.get(msg.what);
        if (met == null) {
            throw new NonExistingWhatException();
        } else {
            met.invoke(AnnotatedHandler.this, msg);
        }
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}
}

MainActivity.java(我的跟踪器应用程序的活动)

公共类MainActivity扩展了SherlockFragmentActivity{
私人行动吧;
私有选项卡mStatTab;
私人选项卡mTrackerTab;
私有服务客户端mClientServiceAPI;
/**
*来自服务的传入消息的处理程序。
*/
公共类MyHandler扩展了AnnotatedHandler{
@执行时间(what=AkrasiaService.TRACKER\u APP\u BACKUP\u RETRIVE)
公共无效把手支架(消息消息消息){
Log.d(“客户机”,“处理消息”);
Bundle=msg.getData();
如果((bundle!=null)&&(!bundle.isEmpty()){
Long timeStamp=bundle.getLong(“上次”);
长色度计时间=bundle.getLong(“色度计时间”);
计时器色度计=(计时器)findViewById(R.id.计时器);
//我们将时间戳和现在之间的时间添加到测氯仪的基础上
Long now=Calendar.getInstance().getTimeInMillis();
色度计时间=现在-时间戳+色度计时间;
色度计设置(色度计时间);
}
}
};
@凌驾
创建时的公共void(Bundle savedInstanceState){
setTheme(com.actionbarsherlock.R.style.Sherlock___主题);
super.onCreate(savedInstanceState);
//请注意,没有使用setContentView(),因为我们使用根目录
//android.R.id.content作为每个片段的容器
//试一试{
//DatabaseFixture.populateDatabase();
//}catch(numberformatexe){
////TODO自动生成的捕捉块
//e.printStackTrace();
//}catch(parsee异常){
////TODO自动生成的捕捉块
//e.printStackTrace();
// }
ApplicationContext.getInstance().setMainActivity(此);
ApplicationContext.getInstance().setupPreferences();
sherlockActionBarSetup();
}
私有void sherlockActionBarSetup(){
mActionBar=getSupportActionBar();
mActionBar.setNavigationMode(ActionBar.NAVIGATION\u MODE\u选项卡);
mActionBar.setDisplayShowTitleEnabled(假);
mActionBar.setDisplayShowHomeEnabled(false);
TabListener trackerTabListener=新的TabListener(此,
“跟踪器”,TrackerFragment.class);
mTrackerTab=mActionBar.newTab().setText(“Track”).setTabListener(trackerTabListener);
mActionBar.addTab(mTrackerTab);
TabListener statablistener=新的TabListener(这是“统计数据”,
StatFragment.class);
mStatTab=mActionBar.newTab().setText(“Stats”).setTabListener(statablistener);
mActionBar.addTab(mStatTab);
}
public void发送回服务(){
Log.d(“客户”,“我们将对色度计进行备份”);
计时器色度计=(计时器)findViewById(R.id.计时器);
Bundle=新Bundle();
bundle.putLong(“上次”,Calendar.getInstance().getTimeInMillis());
bundle.putLong(“色度计时间”,chrometer.getBase());
bundle.putBoolean(“已弃用”,false);
mClientServiceAPI.sendMessage(AkrasiaService.TRACKER\u应用程序\u备份\u刷新,捆绑包);
}
@凌驾
受保护的void onPause(){
super.onPause();
发送回服务();
mClientServiceAPI.doUnbindService(本);
}
@凌驾
受保护的void onStop(){
super.onStop();
mClientServiceAPI.doUnbindService(本);
}
public void restarbackfromservice(视图){
mClientServiceAPI.sendMessage(AkrasiaService.TRACKER\u应用程序\u备份\u检索);
}
@凌驾
受保护的空onDestroy(){
super.ondestory();
mClientServiceAPI.doUnbindService(本);
}
@凌驾
恢复时公开作废(){
super.onResume();
//遗憾的是,此行为无法导出到ServiceClient。
//这是从下面开始的,以前是在onResume方法中
Log.d(“客户端”,“我们将连接到服务”);
mClientServiceAPI=新服务客户端();
setIncomingHandler(新的MyHandler());
Intent Intent=newintent(AkrasiaService.class.getName());
mClientServiceAPI.doBindService(intent,this);
}
/*
*显然,您不能仅将回调绑定到以下片段:
* http://stackoverflow.com/a/6271637/147072
*/
公共无效触发器单击(视图){
TrackerFragment fragment=(TrackerFragment)getSupportFragmentManager().findFragmentByTag(
“追踪器”);
fragment.triggerClick(视图);
}
公共void saveTimeClick(查看){
TrackerFragment fragment=(TrackerFragment)getSupportFragmentManager().findFragmentByTag(
“追踪器”);
试一试{
fragment.saveTimeClick(查看);
}捕获(解析异常){
e、 printStackTrace();
}
//我们重新加载StatFragment,这是为了刷新
//静止碎片
mActionBar.removeTab(mStatTab);
塔布里斯滕
public class AnnotatedHandler extends Handler {

protected HashMap<Integer, Method> magicSwitch = new HashMap<Integer, Method>();

public AnnotatedHandler() {
    try {
        for (Method method : this.getClass().getMethods() ) {
            if (method.isAnnotationPresent(ExecutesWhen.class)) {
                try {
                    ExecutesWhen a = method
                            .getAnnotation(ExecutesWhen.class);
                    magicSwitch.put(a.what(), method);
                    Log.d("AnnotatedHandler","AnnotatedHandler now knows how handle a "+method.getName()+" and id"+a.what());
                } catch (Throwable ex) {
                    ex.printStackTrace();
                }
            }
        }
    } catch (SecurityException e) {
        e.printStackTrace();
    }
}

@Override
public void handleMessage(Message msg) {
    try {
        Log.d("AnnotatedHandler","The service is going to manage a message from the client with what="+msg.what);
        Method met = magicSwitch.get(msg.what);
        if (met == null) {
            throw new NonExistingWhatException();
        } else {
            met.invoke(AnnotatedHandler.this, msg);
        }
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}
public class ServiceClient {
/** Messenger for communicating with service. */
Messenger mServiceConnection = null;

/** Flag indicating whether we have called bind on the service. */
private boolean mIsBound = false;

private Messenger mMessageDispatcher;

/**
 * Class for interacting with the main interface of the service. This callback
 * takes care of setup <code>mServiceConnection</code> and therefore, start to 
 * talk with the service.
 */
private ServiceConnection mConnectionCallback = new ServiceConnection() {
    public void onServiceConnected(ComponentName className,
            IBinder service) {
        mServiceConnection = new Messenger(service);
        Log.d("AkrasiaService","The application is connected to the service now!");
        mIsBound = true;
    }

    public void onServiceDisconnected(ComponentName className) {
        mServiceConnection = null;
    }
};

/**
 * This method makes the binding between the service and the client application.
 * @param intent: An intent of the concrete implementation of the <code>ServiceManager</code>
 * @param activity: The Activity thats want communicate with the service.
 */ 
public void doBindService(Intent intent, Activity activity) { 
    Log.d("AkrasiaService","The application is trying to bind to the service...");
    activity.getApplicationContext().startService(intent);
    activity.bindService(intent, mConnectionCallback, Context.BIND_AUTO_CREATE);
}



public void doUnbindService(Activity activity) {
    if (mIsBound) {
        activity.unbindService(mConnectionCallback);
        mIsBound = false;
    }
}


/**
 * This method sends a single message to the service.
 * @param what: The what (subject) of the message.
 */
public void sendMessage(int what) {
    Message msg = Message.obtain();
    try {
      Bundle bundle = new Bundle();
      msg.setData(bundle);
      msg.what = what;
      msg.replyTo = mMessageDispatcher;
      Log.d("AkrasiaService","The application is going to send a message to the service");
      mServiceConnection.send(msg);
    } catch (RemoteException e) {
      e.printStackTrace();
    }
}

/**
 * This method sends a message to the service with a bundle attached.
 * @param what: The what (subject) of the message.
 * @param bundle: The data bundle attached to the message.
 */
public void sendMessage(int what, Bundle bundle) {
    Message msg = Message.obtain();
    try {
      msg.setData(bundle);
      msg.what = what;
      msg.replyTo = mMessageDispatcher;
      mServiceConnection.send(msg);
    } catch (RemoteException e) {
      e.printStackTrace();
    }
}

public void setIncomingHandler(Handler handler) {
    mMessageDispatcher = new Messenger(handler);
}

public boolean isConnected() {
    return mIsBound;
}
public class MainActivity extends SherlockFragmentActivity {
private ActionBar mActionBar;

private Tab mStatTab;

private Tab mTrackerTab;

private ServiceClient mClientServiceAPI;

/**
 * Handler of incoming messages from service.
 */
public class  MyHandler  extends AnnotatedHandler {
    @ExecutesWhen(what = AkrasiaService.TRACKER_APP_BACKUP_RETRIVE)
    public void handleBackupRestore(Message msg) {
        Log.d("Client","Handling a message");
        Bundle bundle = msg.getData();
        if ((bundle != null) && (!bundle.isEmpty())) {
            Long timeStamp = bundle.getLong("last-time");
            Long chrometerTime = bundle.getLong("chrometer-time");
            Chronometer chrometer = (Chronometer) findViewById(R.id.chronometer);
            //We add the time between the timestamp and now to the chorometer base
            Long now = Calendar.getInstance().getTimeInMillis();
            chrometerTime = now - timeStamp + chrometerTime; 
            chrometer.setBase(chrometerTime);
        }
    }
};

@Override
public void onCreate(Bundle savedInstanceState) {
    setTheme(com.actionbarsherlock.R.style.Sherlock___Theme);
    super.onCreate(savedInstanceState);
    // Notice that setContentView() is not used, because we use the root
    // android.R.id.content as the container for each fragment
    // try {
    // DatabaseFixture.populateDatabase();
    // } catch (NumberFormatException e) {
    // // TODO Auto-generated catch block
    // e.printStackTrace();
    // } catch (ParseException e) {
    // // TODO Auto-generated catch block
    // e.printStackTrace();
    // }
    ApplicationContext.getInstance().setMainActivity(this);
    ApplicationContext.getInstance().setupPreferences();
    sherlockActionBarSetup();
}

private void sherlockActionBarSetup() {
    mActionBar = getSupportActionBar();
    mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    mActionBar.setDisplayShowTitleEnabled(false);
    mActionBar.setDisplayShowHomeEnabled(false);

    TabListener<TrackerFragment> trackerTabListener = new TabListener<TrackerFragment>(this,
            "tracker", TrackerFragment.class);
    mTrackerTab = mActionBar.newTab().setText("Track").setTabListener(trackerTabListener);
    mActionBar.addTab(mTrackerTab);

    TabListener<StatFragment> statTabListener = new TabListener<StatFragment>(this, "stats",
            StatFragment.class);
    mStatTab = mActionBar.newTab().setText("Stats").setTabListener(statTabListener);
    mActionBar.addTab(mStatTab);
}

public void sendBackupToTheService() {
    Log.d("Client","We are going to make a backup of the chromnometer");
    Chronometer chrometer = (Chronometer) findViewById(R.id.chronometer);
    Bundle bundle = new Bundle();
    bundle.putLong("last-time", Calendar.getInstance().getTimeInMillis());
    bundle.putLong("chrometer-time", chrometer.getBase());
    bundle.putBoolean("deprecated", false);
    mClientServiceAPI.sendMessage(AkrasiaService.TRACKER_APP_BACKUP_REFRESH, bundle);
}

@Override
protected void onPause() {
    super.onPause();
    sendBackupToTheService();
    mClientServiceAPI.doUnbindService(this);
}

@Override
protected void onStop() {
    super.onStop();
    mClientServiceAPI.doUnbindService(this);
}

public void restarBackupFromService(View view) {
    mClientServiceAPI.sendMessage(AkrasiaService.TRACKER_APP_BACKUP_RETRIVE);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mClientServiceAPI.doUnbindService(this);
}

@Override
public void onResume() {
    super.onResume();
    //Sadly this behavior can't be exported to ServiceClient.
    //This from below used to be in onResume method
    Log.d("Client","We are going to connect to the service");
    mClientServiceAPI = new ServiceClient();
    mClientServiceAPI.setIncomingHandler(new MyHandler());
    Intent intent = new Intent(AkrasiaService.class.getName());

    mClientServiceAPI.doBindService(intent,this);
}

/*
 * Apparently you can't just tie the callback to the fragment from:
 * http://stackoverflow.com/a/6271637/147072
 */
public void triggerClick(View view) {
    TrackerFragment fragment = (TrackerFragment)getSupportFragmentManager().findFragmentByTag(
            "tracker");
    fragment.triggerClick(view);
}

public void saveTimeClick(View view) {
    TrackerFragment fragment = (TrackerFragment)getSupportFragmentManager().findFragmentByTag(
            "tracker");
    try {
        fragment.saveTimeClick(view);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    // We reload the StatFragment this is to refresh the Graph of the
    // StatFragment
    mActionBar.removeTab(mStatTab);
    TabListener<StatFragment> statTabListener = new TabListener<StatFragment>(this, "stats",
            StatFragment.class);
    mStatTab = mActionBar.newTab().setText("Stats").setTabListener(statTabListener);
    mActionBar.addTab(mStatTab);

}

public void discardTimeClick(View view) {
    TrackerFragment fragment = (TrackerFragment)getSupportFragmentManager().findFragmentByTag(
            "tracker");
    fragment.discardTimeClick(view);
}