• 正确使用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;
    }

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

  • 相关阅读:
    利用Telnet来模拟Http请求 有GET和POST两种
    WebConfig特殊字符的转义!
    userprofile同步用户失败的原因和解决方案
    linux mysql表名大小写
    web.py 中文模版报错
    docker 开启远程
    web.py 笔记
    python 安装influxdb-python
    安装pip
    influxdb 命令
  • 原文地址:https://www.cnblogs.com/pandans/p/2163900.html
Copyright © 2020-2023  润新知