正确使用android的调用机制。

经过一段时间的android代码的摸爬滚大,项目慢慢做大,也许你对android的程序逻辑的处理也慢慢变乱。怎么才能正确应用android的运行时呢?

先总结一下android学习的几个过程,这个也是对照我自己的学习来讲的

1。刚开始摸android控件,熟悉布局,LinearLayout,RelativeLayout,FramLayout。这时候对做出一个优美的界面真是欣喜若狂。慢慢的发现怎么qq能做出这种效果,怎么htc的tab能够这样。于是开始思考,怎么能够自定义控件,怎么能够做出更好看的界面。于是开始研究。。反编译。。模仿。。

2。逐渐也能够模仿出别人写的优美的控件了。这是感觉自己就会android。高手了。。可以做高级的项目了。

3。一开始工作发现,哇,傻了。界面都弄好了,但是功能怎么实现呢?怎么从一个Activity传递给另外一个acitivity数据啊,傻了,仓皇之下马上谷哥,百度了。发现intent可以传,好,就用intent,一段时候后就编织了一道intent传递网了。总感觉这样太麻烦了,有些东西还用intent传不了的,这下麻烦了。又开始研究怎么传传不了的东西,于是开始学习使用序列化,使用Parcelable接口。嗯,不错都能满足要求 。

4。渐渐发现就这样传来传去到底还是一次性的,程序关闭再打开就没有办法了。于是想到了sharePreference,sqlite,sharePreference这个就方便多了,有什么直接扔到里面,commit一下,下次直接取就是。sqlite这个还是有点麻烦的,db啊,又要设计表,又要搞查询,插入什么的,于是开始建立数据库开始写sqlite语句了,永久保存数据这下是没问题啦,直接使用数据库好生快活!。。慢慢发现android又出现了一个Cursor于是奇怪了

为什么要用cursor呢?cursor是一个数据集,通过sql语句查询出来的,可以很简便的结合CursorAdapter系列使用,也可很方便的从数据库中得到。

但是问题又来了,老会报cursor未关闭,数据库未关闭的错误,比如有个列表绑定了cursor,你又不能取得了cursor直接关闭db,这下纠结了, 到底什么时候关数据库呢,到底cursor改怎么用呢?一怒之下改成从cursor取出数据后直接拿个变量来接受了,省得麻烦。气死了。。这样也行,但是心中老存在着隐患,这要比人家多多少内存啊!!mygad。。不过也没办法。

5。于是思考人家google都用的好好的,我干嘛就用不好呢?发现原来还有DB provider这种东西,它就不用考虑何时关db何时开db的问题了。只要管好你用的cursor就行了。。哎呀,解决心头痛啊,问题似乎找到解决办法了。后面才发现contentprovider不是这么好用的啊。这个数据一多,查询一多咱都要疯了。。好吧,慢慢练吧!

6。这些东西慢慢都每问题了,做一般的问题也每问题了,后台能跑这种问题的出现于是给平静的代码生活激荡出了轩然大波,开始研究service,一直听别人说service能在后台运行,就用呗。用着用着发现,不对还有一种叫aidl的东西,这下搞不清楚了,怎么传递数据呢?乱套了。。然后出现一堆的bindservice,一堆的aidl。

Service获得Activity的数据
1、在startService或者bindService的时候,通过在Intent中加入bundle来给service传递数据;
2、bindService的时候,在ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法中,通过IBinder中的Setter方法来给Service传递数据,也可以直接将Activity的引用传递给Service,这样Service就可以操作Activity中数据和方法了。
3、通过SharedPerferences共享存储数据;
4、通过Sqlite数据库存储和获取数据,可以实现数据共享;
5、其他数据方法,如Files等,具体内容看文档的Dev guide->data storage部分吧。

Activity获得Service的数据

1、同上通过sharedPerferences,sqlite,files等共享数据;
2、bindService的时候,在ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法中,通过IBinder可以访问Service的方法和变量,具体:
a. 在自定义的IBinder中通过getter方法,返回Service中的变量,在赋给Activity中的的变量或者引用。
b. 在自定义的IBinder中的方法,执行Service中的操作;
c. 在自定义的IBinder中通过方法返回Service的引用,赋给Activity中Service引用,这样Activity就可以对Service进行操作了。

7。一段时间后以上代码自己都看不懂了。于是找另外一种方法,单例。哪里都可以随便调,这个就方便多了,Application也开始泛滥使用了。也就纳闷了android要弄出个service干嘛。。又发现有些时候程序没使用service那么稳固,使用service肯定有它的先进性。

使用service和使用单例类有什么不同?

在android存在许多单例类,如application,你也可以在程序中定义单例类,使用单例类设置监听器同样能够在后台或者说是application还没有被杀死的情况下回调,触发事件来运行您设定的业务逻辑,使用单例类,你可以在程序的任意一个地方,调用单例类的函数,变量,而且还不需要再写n多让你觉得担忧的static变量及方法,而且可以让你安心的把临时变量堆在一个地方。刚开始使用service的时候或许很多童鞋都对bind,start,aidl的概念搞得稀里糊涂,会觉得service真是个难搞的东西,单例多么完美啊,随便调用!看似很完美~~

那么android为什么偏要弄出一个service来呢?看service首先要看Activity,所有能看得懂这篇文章的人应该对activity都比较熟悉了。Activity在android中有它的生命周期,service也一样,service在android中的周期作为开发者你你是很容易控制的,start它就启动了,stop就关了。而单例呢?你根本就没办法准确的控制它的周期,什么时候生,什么时候死都无法准确掌握,那你还想它能够给你多稳定呢!而且在application中许多要用到异步处理的地方你都很尴尬的开出n多线程。new Thread(new Runnable()).start()调的自己都看不下去了。

8。慢慢的理解了更多,之道handler的使用,知道HandlerThread的异步,知道外部Activity可以重复调用start把参数传递service通过handler传给handlerThread在它的里面异步处理了。慢慢的知道可以使用boardcast出来,提醒外部要刷新了。这里我说一下现在我觉得不错的框架:

《1》通过alertmanager启动一个service并设定重启时间,这样没过一段时间就会重复启动service,如果service已经启动则直接调用start,如此可以防止三方软件kill你的应用。

    public static void alertEngineOn() {
Context mContext
= ImBeta.getContext();
// Schedule the alarm!
PendingIntent mAlarmSender = PendingIntent.getService(mContext, 0,
new Intent(mContext, HandCentImService.class), 0);
// We want the alarm to go off 30 seconds from now.
long firstTime = SystemClock.elapsedRealtime();
AlarmManager am
= (AlarmManager) mContext
.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime,
5 * 1000 * 60, mAlarmSender);
}

《2》service中注册一个ThreadHandler,Activity想调用Service的函数是,将参数和想调用的方法的key传入,在start()中用handler接受,并

        HandlerThread thread = new HandlerThread("",
android.os.Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper
= thread.getLooper();
mServiceHandler
= new ServiceHandler(mServiceLooper);

Message msg
= mServiceHandler.obtainMessage();
msg.what
= ACTION_START;
mServiceHandler.sendMessage(msg);

然后在handler中对相应的消息调用不同的函数,你可以写一些业务类,处理,不用把所有函数都扔service,看着就舒服多了

    private class ServiceHandler extends Handler {

public ServiceHandler(Looper looper) {
super(looper);
}

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int msgType = msg.what;
Intent intent
= (Intent) msg.obj;
switch (msgType) {
case ACTION_START:
// 获取服务器和端口号
if (mXmppService.isRegister()) {
// TODO 如果已经注册则发送ping消息包
}
IMUtil.getConnectionInfo(mContext);
mXmppService.start();
// mXMPPStartWorkThread.start();
break;
case ACTION_MSG_SENDMSG:
// 队列
mXmppService.sendChatStackMsg();
System.out.println(
"start sending messages");
// mQueueWorkThread.start();
break;
case ACTION_MSG_COMPOSING:
// 发送正在编辑消息通知
// mXmppService.sendComposingState(intent.getStringExtra(KEY_JID));
break;
case ACTION_MSG_CANCEL:
// 发送编辑停止通知
// mXmppService.sendComCancelState(intent.getStringExtra(KEY_JID));
break;
case ACTION_ROSTER_ADDROSTER:
mXmppService.addRoster(intent.getStringExtra(KEY_JID),
intent.getStringExtra(KEY_ROSTER_NAME));
break;
case ACTION_ROSTER_REMOVEROSTER:
mXmppService.removeRoster(intent.getStringExtra(KEY_JID),
intent.getStringExtra(KEY_ROSTER_NAME));
break;
case ACTION_ROSTER_SUBSCRIBE:
Presence.Type mType
= Presence.Type.valueOf(intent
.getStringExtra(KEY_PRESENCE_STATUS));
mXmppService.sendSubResponse(mType);
break;
case ACTION_ROSTER_REMANEMROSTER:
mXmppService.removeRoster(intent.getStringExtra(KEY_JID),
intent.getStringExtra(KEY_ROOM_NAME));
break;
case ACTION_ROOM_CREATROOM:
mXmppService.createMUCRoom(intent.getStringExtra(KEY_ROOM_ID),
intent.getStringExtra(KEY_ROOM_NAME),
intent.getStringExtra(KEY_ROOM_DESC));
break;
case ACTION_ROOM_REMOVEROOM:
mXmppService.removeMUCRoom(intent.getStringExtra(KEY_ROOM_ID));
break;
case ACTION_ROOM_GRANTMEMBER:
mXmppService.addMemberForRoom(
intent.getStringExtra(KEY_ROOM_ID),
intent.getStringExtra(KEY_ROOM_NAME),
intent.getStringExtra(KEY_ROOM_DESC),
intent.getStringExtra(KEY_JID));
break;
case ACTION_SENDPRESENCE:
Presence.Type pretype
= Presence.Type.valueOf(intent
.getStringExtra(KEY_PRESENCE_STATUS));
mXmppService.setPresence(pretype,
intent.getStringExtra(KEY_PRESENCE_SIGNATURE));
break;
case ACTION_NETCHANGE:
// 重连通知
// mXmppService.setNetConnected(intent.getBooleanExtra(
// KEY_NETWORK, false));
// 网络中断了一下,先关闭所有连接
mXmppService.setNetConnected(nowNetWorkEnable);
break;
case ACTION_CLOAED:
// mXmppService.stop();
stopSelf();
// alertEnineOff();
break;
case ACTION_JOIN_ROOM_LISTS:
mXmppService.joinRoomLists();
break;
case ACTION_JOIN_ROOM:
mXmppService.joinRoom(intent.getStringExtra(KEY_ROOM_ID));
break;

case ACTION_UPDATE_PRESENCE:
mXmppService.getPresence(intent.getStringExtra(KEY_JID));
break;
default:
break;
}
}
}

逻辑简单了吧。

《3》Activity大多不就是显示一些列表啊什么的,在service的处理中吧数据缓存到数据库中,不适合存数据库的可以使用之前的单例类存储内存缓存数据。在你需要调用的任何地方直接query或者getInstance就可以轻易的访问了。。这里就不用多说了。

《4》记得最后要把alertmanager弄掉啊。不然你程序就只能卸载才能停了

    /**
* 关闭定时器,关闭服务。
*/
public static synchronized void alertEnineOff() {
Context mContext
= ImBeta.getContext();
PendingIntent mAlarmSender
= PendingIntent.getService(mContext, 0,
new Intent(mContext, HandCentImService.class), 0);
AlarmManager am
= (AlarmManager) mContext
.getSystemService(Context.ALARM_SERVICE);
am.cancel(mAlarmSender);
mAlarmSender
= null;
HandCentIntentUtil.getStopIntent(ImBeta.getContext());
CommonConfig.setServiceCancel(ImBeta.getContext(),
true);
}

《5》很多地方需要用到Content,acivity中好说,其他地方试试getApplicationContext()或者试试自己继承Application写一个getContext()方法返回该App

public class ImBeta extends Application {
private static ImBeta mBetaInstance;

public ImBeta() {
super();
mBetaInstance
= this;
}

public static ImBeta getInstance() {
return mBetaInstance;
}

好,以上是我的一点点新的心得,仅供参考,如有不妥大牛请斧正。。哈哈

原文地址:https://www.cnblogs.com/pandans/p/2163900.html