Android有四大组件:Activity、Service、Broadcast Receiver、Content Provider。

Activity

概述:    Activity是android中使用比较频繁的一个组件,使用它需要在AndroidManifest中进行声明。Activity    是Android程序与用户交互的窗口,从这个角度看来,可以类比为做网站的页面,既然是页面,无疑是最耗    时也是最复杂的。
  • 说起Activity,那么第一步必不可少的就是了解Activity的生命周期了。
Paste_Image.png

从上图可以看到Activity的七种生命周期相关的方法从上到下依次是:

  • onCreate():Activity首次创建的时候调用,在这个方法中,通常调用setContentView(int)方法,传入你所需要的UI效果的layout资源布局,findViewById(int)来检索在布局中你需要用到的窗体小部件。
  • onRestart():在Actually停止后,再次被启动前调用。
  • onStart():界面对用户而言可见的时候调用。
  • onResume():用户获得焦点的时候。
  • onPause():用户失去焦点。
  • onStop():界面不可见。
  • onDestory():退出应用程序的时候。

总结:

  简单的说,分为三种大状态:   1. Activity刚启动的时候:Android系统会依次调用onCreate(),onStart(),onResume().   2. 暂停状态:当有另一个Activity来到最前端显示的时候, 进要进入暂停状态,要停留在暂停状态, 就需要新展现到前端的Activity是部分遮盖当前Activity的.也就是说, 在当前的Activity之上有一个Activity, 这个Activity类似于一个小窗口,只遮住了当前Activity的一小部分。当用户从小窗口退出回到当前的Activity的时候,当前的Activity就会从onPause()状态恢复到onResume()状态,这时Android系统会调用onResume()。   3.停止状态:如果当前新获得焦点的Activity把当前Activity完全覆盖的话, 当前Activity就进入了停止状态。通常有两种情形:一种是用户退出程序,另一种是,当前Activity被新获得焦点的Activity完全覆盖住了。如果是第一种情形,系统会调用onDestory()执行销毁当前的Activity,当前Activity对象会从内存中销毁。如果是第二种情形,那么此时当前Activity会保持在栈中,如果用户把新来的Activity退出,系统会回退到当前的Activity,就会执行onRestart(),onStart(),onResume()。                  

Activity启动模式

Android系统是通过任务栈来管理Activity的,当一个Activity启动时,会把它压入到该Task的堆栈中,当用户按返回键或者结束该Activity时,它会从该Task的堆栈中弹出,Android系统默认的任务栈模式采用"后进先出"的原则,Android中为我们定义了如下的四种加载模式。1.standard模式:Activity默认的加载模式,当使用意图(Intent)等方法启动一个Activity的时候, 就创建一  个新的Activity, 并放入  栈的最顶端。2.singleTop模式: 如果当前栈顶是新创建的Activity时, 就不创建新的Activity, 而是直接调用栈顶的这个  Activity,如果栈顶不是当前需要的Activity时, 就创建一个。3.singleTask模式:如果当前系统中不存在当前需要的Activity时, 就创建一个新的Activity放入最顶端,  如果存在的话, 就把位于栈中的这个Activity之上的所有Activity全部销毁, 然后调用这个Activity并显示。4.singleInstance模式:如果当前系统中不存在当前需要的Activity时, 就创建一个新的,如果存在所需要的  Activity时, 就把系统中存在的Activity从栈中提取出来, 然后放入栈的最顶端。

Activity需要注意的一些细节

1· 在Activity中是不适合做一些太耗时的操作的。不要在子线程中修改UI。2. 注意onDestory()方法中一些资源的释放,比如网络请求,当Activity销毁的时候,都应当取消该次请求,   避免界面已经销毁而网络请求仍然在执行,导致下个界面请求。比如一些对象资源的显示回收,如图片等。

Service

概述: Service不像Activity那样,它不直接与用户进行交互,因此没有用户界面,能够长期在后台运行,且      比Activity具有更高的优先级,在系统资源紧张时不会轻易被Android系统终止。Service不仅可以实      现后台服务的功能,也可以用于进程间的通信(AIDL)。使用Service时,同样需要在AndroidManifest      中进行声明。

Service生命周期:

服务的开启有两种方式,第一种开启方式是startService()开始,stopSrvice()结束;另一种开始方式是,始于bindService(),终于unbindService()。所以以不同的方式开启Service,生命周期略有不同。
Paste_Image.png

Code:

  • 本地服务:
public class LocalService extends Service {
    private NotificationManager mNM;    // Unique Identification Number for the Notification.    // We use it on Notification start, and to cancel it.    private int NOTIFICATION = R.string.local_service_started;       /**     * Class for clients to access.  Because we know this service always     * runs in the same process as its clients, we don't need to deal with     * IPC.     */    public class LocalBinder extends Binder {        LocalService getService() {            return LocalService.this;        }    }
    @Override    public void onCreate() {        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        // Display a notification about us starting.  We put an icon in the status bar.        showNotification();    }
    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.i("LocalService", "Received start id " + startId + ": " + intent);        return START_NOT_STICKY;    }
    @Override    public void onDestroy() {        // Cancel the persistent notification.        mNM.cancel(NOTIFICATION);
        // Tell the user we stopped.        Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show();    }
    @Override    public IBinder onBind(Intent intent) {        return mBinder;    }
    // This is the object that receives interactions from clients.  See    // RemoteService for a more complete example.    private final IBinder mBinder = new LocalBinder();
    /**     * Show a notification while this service is running.     */    private void showNotification() {        // In this sample, we'll use the same text for the ticker and the expanded notification        CharSequence text = getText(R.string.local_service_started);
        // The PendingIntent to launch our activity if the user selects this notification        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,                new Intent(this, LocalServiceActivities.Controller.class), 0);
        // Set the info for the views that show in the notification panel.        Notification notification = new Notification.Builder(this)                .setSmallIcon(R.drawable.stat_sample)  // the status icon                .setTicker(text)  // the status text                .setWhen(System.currentTimeMillis())  // the time stamp                .setContentTitle(getText(R.string.local_service_label))  // the label of the entry                .setContentText(text)  // the contents of the entry                .setContentIntent(contentIntent)  // The intent to send when the entry is clicked                .build();
        // Send the notification.        mNM.notify(NOTIFICATION, notification);    }}
  • write client code that directly accesses the running service, such as:
    private LocalService mBoundService;    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.  Because we have bound to a explicit        // service that we know is running in our own process, we can        // cast its IBinder to a concrete class and directly access it.        mBoundService = ((LocalService.LocalBinder)service).getService();
        // Tell the user about this for our demo.        Toast.makeText(Binding.this, R.string.local_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.        // Because it is running in our same process, we should never        // see this happen.        mBoundService = null;        Toast.makeText(Binding.this, R.string.local_service_disconnected,                Toast.LENGTH_SHORT).show();    }    };
    void doBindService() {    // Establish a connection with the service.  We use an explicit    // class name because we want a specific service implementation that    // we know will be running in our own process (and thus won't be    // supporting component replacement by other applications).    bindService(new Intent(Binding.this,             LocalService.class), mConnection, Context.BIND_AUTO_CREATE);    mIsBound = true;    }
    void doUnbindService() {        if (mIsBound) {            // Detach our existing connection.            unbindService(mConnection);            mIsBound = false;        }    }
    @Override    protected void onDestroy() {        super.onDestroy();        doUnbindService();    }  }    
  • 远程服务(AIDL)
  public class MessengerService extends Service {    /** For showing and hiding our notification. */    NotificationManager mNM;    /** Keeps track of all current registered clients. */    ArrayList mClients = new ArrayList();    /** Holds last value set by a client. */    int mValue = 0;
    /**     * Command to the service to register a client, receiving callbacks     * from the service.  The Message's replyTo field must be a Messenger of     * the client where callbacks should be sent.     */    static final int MSG_REGISTER_CLIENT = 1;
    /**     * Command to the service to unregister a client, ot stop receiving callbacks     * from the service.  The Message's replyTo field must be a Messenger of     * the client as previously given with MSG_REGISTER_CLIENT.     */    static final int MSG_UNREGISTER_CLIENT = 2;
    /**     * Command to service to set a new value.  This can be sent to the     * service to supply a new value, and will be sent by the service to     * any registered clients with the new value.     */    static final int MSG_SET_VALUE = 3;
    /**     * Handler of incoming messages from clients.     */    class IncomingHandler extends Handler {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case MSG_REGISTER_CLIENT:                    mClients.add(msg.replyTo);                    break;                case MSG_UNREGISTER_CLIENT:                    mClients.remove(msg.replyTo);                    break;                case MSG_SET_VALUE:                    mValue = msg.arg1;                    for (int i=mClients.size()-1; i>=0; i--) {                        try {                            mClients.get(i).send(Message.obtain(null,                                    MSG_SET_VALUE, mValue, 0));                        } catch (RemoteException e) {                            // The client is dead.  Remove it from the list;                            // we are going through the list from back to front                            // so this is safe to do inside the loop.                            mClients.remove(i);                        }                    }                    break;                default:                    super.handleMessage(msg);            }        }    }
    /**     * Target we publish for clients to send messages to IncomingHandler.     */    final Messenger mMessenger = new Messenger(new IncomingHandler());>      @Override    public void onCreate() {        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        // Display a notification about us starting.        showNotification();    }
    @Override    public void onDestroy() {        // Cancel the persistent notification.        mNM.cancel(R.string.remote_service_started);
        // Tell the user we stopped.        Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show();    }
    /**     * When binding to the service, we return an interface to our messenger     * for sending messages to the service.     */    @Override    public IBinder onBind(Intent intent) {        return mMessenger.getBinder();    }
    /**     * Show a notification while this service is running.     */    private void showNotification() {        // In this sample, we'll use the same text for the ticker and the expanded notification        CharSequence text = getText(R.string.remote_service_started); >         // The PendingIntent to launch our activity if the user selects this notification        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,                new Intent(this, Controller.class), 0);>          // Set the info for the views that show in the notification panel.        Notification notification = new Notification.Builder(this)                .setSmallIcon(R.drawable.stat_sample)  // the status icon                .setTicker(text)  // the status text                .setWhen(System.currentTimeMillis())  // the time stamp                .setContentTitle(getText(R.string.local_service_label))  // the label of the entry                .setContentText(text)  // the contents of the entry                .setContentIntent(contentIntent)  // The intent to send when the entry is clicked                .build();
        // Send the notification.        // We use a string id because it is a unique number.  We use it later to cancel.        mNM.notify(R.string.remote_service_started, notification);    }  }
  • clients can now bind to the service and send messages to it. Note that this allows clients to register with it to receive messages back as well
/** Messenger for communicating with service. */
Messenger mService = null;/** Flag indicating whether we have called bind on the service. */boolean mIsBound;/** Some text view we are using to show state information. */TextView mCallbackText;
/** * Handler of incoming messages from service. */class IncomingHandler extends Handler {    @Override    public void handleMessage(Message msg) {        switch (msg.what) {            case MessengerService.MSG_SET_VALUE:                mCallbackText.setText("Received from service: " + msg.arg1);                break;            default:                super.handleMessage(msg);        }    }}
/** * Target we publish for clients to send messages to IncomingHandler. */final Messenger mMessenger = new Messenger(new IncomingHandler());
/** * 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 = new Messenger(service);    mCallbackText.setText("Attached.");
    // We want to monitor the service for as long as we are    // connected to it.    try {        Message msg = Message.obtain(null,                MessengerService.MSG_REGISTER_CLIENT);        msg.replyTo = mMessenger;        mService.send(msg);
        // Give it some value as an example.        msg = Message.obtain(null,                MessengerService.MSG_SET_VALUE, this.hashCode(), 0);        mService.send(msg);    } 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(Binding.this, R.string.remote_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(Binding.this, R.string.remote_service_disconnected,            Toast.LENGTH_SHORT).show();}};
void doBindService() {// Establish a connection with the service.  We use an explicit// class name because there is no reason to be able to let other// applications replace our component.bindService(new Intent(Binding.this,         MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);mIsBound = true;mCallbackText.setText("Binding.");}
void doUnbindService() {if (mIsBound) {    // If we have received the service, and hence registered with    // it, then now is the time to unregister.    if (mService != null) {        try {            Message msg = Message.obtain(null,                    MessengerService.MSG_UNREGISTER_CLIENT);            msg.replyTo = mMessenger;            mService.send(msg);        } catch (RemoteException e) {            // There is nothing special we need to do if the service            // has crashed.        }    }
    // Detach our existing connection.    unbindService(mConnection);    mIsBound = false;    mCallbackText.setText("Unbinding.");  }}

Broadcast Receiver

概述:Android系统中有各式各样的广播,比如电话或者短信都会产生一个广播,当应用程序运行的时候就会向      Android注册各种广播,主要的两种广播类型是:一种是非常驻型广播,此类广播会伴随应用程序的生命      周期;另一种是常驻型广播,这类广播不会随着应用程序是否关闭而存在,只要有广播来就会被系统调用      自动运行。Android系统接收到广播后,便会对广播进行判断,找出所需的事件,然后向不同的应用程序      注册事件。不同的广播可以处理不同的广播事件,也可以处理相同的广播事件,广播接受者的时候用往往      伴随着权限的声明,当然也别忘了在AndroidManifest中注册广播。

定义一个广播接受者很容易,有动态注册(非常驻型广播)还有静态注册(常驻型广播),动态注册的优先级高于静态注册的优先级。

静态注册广播接收者通常只需要两步走:

  • 编写一个类继承BroadcastReceiver, 并重写其中的onReceive方法, 在该方法中编写自己的业务逻辑代码。
  • 在AndroidManifest中进行注册。在Application节点下声明一个节点, 在该节点下可以添加"android:priority"来指定当前广播接收者的优先权,在节点下添加子节点, 用来指定当前"接受者"所接收的广播的类型,如果想要接收的广播类型在定义的时候指定了需要的权限, 则需要在配置清单中申请该权限, 才可以接收该广播并进行操作。

eg: 以接收短信为里,在AndroidManifest中注册下。

             //这里指定接收的广播类型...        //广播类型既可以是系统广播, 也可以是自己创建的广播        

动态注册广播接受者:
简单的说就是通过使用ContentWrapper.registerReceive()方法来注册BroadcastReceive。

eg:发送自定义静态注册广播消息(或者系统广播)

Intent intent = new Intent();intent.setAction("your  custom receive name");      //设置Actionintent.putExtra("msg", "接收静态注册广播成功!");  //添加附加信息sendBroadcast(intent);  

eg:注册广播实现监听:

IntentFilter intentFilter = new IntentFilter();//广播过滤器intentFilter.addAction("AndroidManifest中声明的自定义的或系统的广播名");intentFilter.setPriority(Integer.MAX_VALUE);  //设置广播优先级(动态时 -1000 至 1000,静态注册最大可达到Integer.MAX_VALUE)registerReceiver(new MyBroadcastReciver(), intentFilter);//注册广播

Content Provider

概述:    1.Android中的ContentProvider机制可支持在多个应用中存储和读取数据,这也是跨应用共享数据的唯一      方式,常见的通讯录功能就是采用的这个机制。这些相关的信息可以在android.provider包下找到一些      Android提供的ContentProvider,通过它们提供的地址并且获取到相应的权限之后,就可以获得这些      ContentProvider,从而可以使用ContentResolver对象,通过对URI来操作数据。   2. 在Android中,如果想公开自己的数据 ,供其他的应用程序使用,那么有两种方法:一是创建自己的      ContentProvider,需要继承系统的ContentProvider类;二是如果你的数据和Android已提供的存在的      ContentProvider的数据结构一致的话,就可以将数据写到已存在的ContentProvider中,当然一般这些      操作都需要一定的权限,记得在AndroidManifest中声明所需要的权限。

URI通用资源标识符介绍

 eg: 所有联系人的Uri: content://contacts/people 某个联系人的Uri: content://contacts/people/5 所有图片Uri: content://media/external 某个图片的Uri:content://media/external/images/media/4Uri组成部分: A:无法改变的标准前缀:如:"content://","tel://"等,当前缀是"content://"时,说明可通过   ContentProvider控制这些数据。 B:URI的标识,它通过authorities属性声明限制一个类的访问,用于限制是哪个ContentProvider能够有权    限提供这些数据。对于第三方应用程序,为了保证URI的唯一性,它必须是完整的类名。 C:路径,可以近似地理解为需要操作的数据库中表的名字。 D:如果URI中包含表示需要获取的记录的ID,则返回该ID对应的数据,如果没有ID,就表示返回全部。因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris。1.UriMatcher常用的方法:  1.1 public void addURI(String authority,String path, int code): UriMatcher是一个Uri的容器      ,这个容器里面包含着即将可能要操作的Uri,它用于业务逻辑的处理,path相当于Uri中上述所说的路径      ,也就是想要操作的数据表名,第三个参数code,如果通过下面的match()方法匹配成功就返回这个code值。  1.2 public int match(Uri uri):与传入的Uri匹配,它会首先与找之前通过addURI方法添加进来的Uri匹配      ,如果匹配成功就返回之前设置的code值,否则返回一个值-1的常量UriMatcher.NO_MATCH。2.ContentUris常用的方法:  2.1 public static Uri withAppendedId(Uri contentUri,long id):用于为路径加上ID。  2.2 public static long parseId(Uri contentUri):用于从路径中获取ID。

ContentProvider核心类常用方法:

1.public abstract boolean onCreate(): 在ContentProvider创建后被调用。2.public abstract Uri insert(Uri uri,ContentValues values):根据Uri插入Values对应的数据。3.public abstract int delete(Uri uri,String selection,String[] selectionArgs):根据Uri删除  selection指定条件所匹配的全部记录。4.public abstract int update (Uri uri, ContentValues values, String selection, String[]   selectionArgs):根据Uri修改selection指定条件所匹配的全部记录。5.public abstract Cursor query (Uri uri, String[] projection, String selection, String[]    selectionArgs, String sortOrder):根据Uri查询出selection指定条件所匹配的全部记录,并且可以   指定查询哪些列(projection)以什么方式(sortOrder)排序。6.public abstract String getType (Uri uri):返回当前Uri所指向数据的MIME类型,MIME类型由自己进  行定义。如果该Uri对应的数据包括多条记录,那么MIME类型的字符串就以 vnd.android.cursor.dir/开头,  如果Uri对应的数据只包含一条记录,那么MIME类型的字符串就以vnd.android.cursor.item/开头,这样系  统能够识别对应的MIME类型,在执行query()方法返回Cursor对象的时候,系统将不需要再进行验证,若返回  的字符串不能被系统识别,在执行query()方法返回Cursor对象的时候将需要再进行验证。

以Android系统的通讯录为例

1.首先需要再在AndroidManifest中添加读写通讯录的权限。

  

2.查看Android系统源码看下Android系统共享的一些数据,从模拟器中可以查看到相应的共享的信息。

Paste_Image.png
3.找到通讯录,观看通讯录的表结构
Paste_Image.png

  • data表:记录了用户的通讯录所有数据,包括手机号,显示名称等,但是里面的mimetype_id表示不同的数据类型。这与表mimetypes表中的_id相对应。raw_contact_id与下面的raw_contacts表中的_id相对应。
Paste_Image.png
  • groups表,此表记录的是通讯录中的分组,其中account_name标识了这个分组属于那个用户。在字段中有一个group_visible标识了当前组是否可见(0表示可见,1表示隐藏)


    Paste_Image.png
  • mimetypes表:

Paste_Image.png
  • raw_contacts表中,有一个字段是contact_id,接下来会与下面的contacts表中的_id相关联。


    Paste_Image.png
  • contacts表,这个表中的name_raw_contact_id就与上面的raw_contacts表中的_id相对应。


    Paste_Image.png
  • 通讯录中显示的手机号存放在data表中,而对应的用户显示名称却是在raw_contacts中,所以当我们要去获取手机号对应的用户显示名称的时候,我们还需要去查看raw_contacts表中的值,这个中间对应的桥梁就是data表中raw_contact_id

4.操作Android系统的通讯录数据库的方法(改天写个通讯录Demo出来)。

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. 一句话锁定MySQL数据占用元凶
  3. Android(安卓)危险权限、权限组列表和所有普通权限
  4. android 电话状态的监听(来电和去电)
  5. android Service与BroadcastReceiver
  6. Android(安卓)Configuration系统设置
  7. Android保存图片到系统相册并更新
  8. ListView 使用详解
  9. 部分 CM11 系统 Android(安卓)平板运行植物大战僵尸 2 黑屏的解

随机推荐

  1. Android中TextView输入字数统计和限制 &
  2. Android中去除标题,全屏,获得屏幕方向及键
  3. Android(安卓)Sqlite的使用
  4. Android程式编写及调试新手入门-1
  5. Android插件化开发之DexClassLoader动态
  6. android按键移植
  7. Android架构组件(三)——ViewModel
  8. Android(安卓)运行底层linux外部命令的实
  9. 相对布局
  10. 如何获得Android手机的软件安装列表