方向比努力重要,能力比知识重要,情商比智商重要!
随笔- 43 文章- 0 评论- 12
注:本文来自“友盟杯”,仅在此阅读,学习
这个文章主要是讲的四大组件,本文主要分为
一、Activity详解二、Service详解三、Broadcast Receiver详解四、Content Provider详解外加一个重要组件 intent的详解。一、Activity详解Activty的生命周期的也就是它所在进程的生命周期。 一、 onCreate :当活动第一次启动的时候,触发该方法,可以在此时完成活动的初始化工作。 onCreate 方法有一个参数,该参数可以为空( null ),也可以是之前调用 onSaveInstanceState ()方法保存的状态信息。
二、 onStart :该方法的触发表示所属活动将被展现给用户。
三、 onResume :当一个活动和用户发生交互的时候,触发该方法。
四、 onPause :当一个正在前台运行的活动因为其他的活动需要前台运行而转入后台运行的时候,触发该方法。这时候需要将活动的状态持久化,比如正在编辑的数据库记录等。
五、 onStop :当一个活动不再需要展示给用户的时候,触发该方法。如果内存紧张,系统会直接结束这个活动,而不会触发 onStop 方法。 所以保存状态信息是应该在onPause时做,而不是onStop时做。活动如果没有在前台运行,都将被停止或者Linux管理进程为了给新的活动预留足够的存储空间而随时结束这些活动。因此对于开发者来说,在设计应用程序的时候,必须时刻牢记这一原则。在一些情况下,onPause方法或许是活动触发的最后的方法,因此开发者需要在这个时候保存需要保存的信息。
六、onRestart :当处于停止状态的活动需要再次展现给用户的时候,触发该方法。
七、 onDestroy :当活动销毁的时候,触发该方法。和 onStop 方法一样,如果内存紧张,系统会直接结束这个活动而不会触发该方法。
· onSaveInstanceState :系统调用该方法,允许活动保存之前的状态,比如说在一串字符串中的光标所处的位置等。 通常情况下,开发者不需要重写覆盖该方法,在默认的实现中,已经提供了自动保存活动所涉及到的用户界面组件的所有状态信息。
Activity栈
上面提到开发者是无法控制Activity的状态的,那Activity的状态又是按照何种逻辑来运作的呢?这就要知道 Activity 栈。 每个Activity的状态是由它在Activity栈(是一个后进先出LIFO,包含所有正在运行Activity的队列)中的位置决定的。 当一个新的Activity启动时,当前的活动的Activity将会移到Activity栈的顶部。 如果用户使用后退按钮返回的话,或者前台的Activity结束,活动的Activity就会被移出栈消亡,而在栈上的上一个活动的Activity将会移上来并变为活动状态。如下图所示: 一个应用程序的优先级是受最高优先级的Activity影响的。当决定某个应用程序是否要终结去释放资源,Android内存管理使用栈来决定基于Activity的应用程序的优先级。 Activity状态 一般认为Activity有以下四种状态: 活动的:当一个Activity在栈顶,它是可视的、有焦点、可接受用户输入的。Android试图尽最大可能保持它活动状态,杀死其它Activity来确保当前活动Activity有足够的资源可使用。当另外一个Activity被激活,这个将会被暂停。 暂停:在很多情况下,你的Activity可视但是它没有焦点,换句话说它被暂停了。有可能原因是一个透明或者非全屏的Activity被激活。 当被暂停,一个Activity仍会当成活动状态,只不过是不可以接受用户输入。在极特殊的情况下,Android将会杀死一个暂停的Activity来为活动的Activity提供充足的资源。当一个Activity变为完全隐藏,它将会变成停止。 停止:当一个Activity不是可视的,它“停止”了。这个Activity将仍然在内存中保存它所有的状态和会员信息。尽管如此,当其它地方需要内存时,它将是最有可能被释放资源的。当一个Activity停止后,一个很重要的步骤是要保存数据和当前UI状态。一旦一个Activity退出或关闭了,它将变为待用状态。 待用: 在一个Activity被杀死后和被装在前,它是待用状态的。待用Acitivity被移除Activity栈,并且需要在显示和可用之前重新启动它。 activity的四种加载模式 在android的多activity开发中,activity之间的跳转可能需要有多种方式,有时是普通的生成一个新实例,有时希望跳转到原来某个activity实例,而不是生成大量的重复的activity。加载模式便是决定以哪种方式启动一个跳转到原来某个Activity实例。 在android里,有4种activity的启动模式,分别为: ·standard: 标准模式,一调用startActivity()方法就会产生一个新的实例。 ·singleTop: 如果已经有一个实例位于Activity栈的顶部时,就不产生新的实例,而只是调用Activity中的newInstance()方法。如果不位于栈顶,会产生一个新的实例。 ·singleTask: 会在一个新的task中产生这个实例,以后每次调用都会使用这个,不会去产生新的实例了。 ·singleInstance: 这个跟singleTask基本上是一样,只有一个区别:在这个模式下的Activity实例所处的task中,只能有这个activity实例,不能有其他的实例。 这些启动模式可以在功能清单文件AndroidManifest.xml中进行设置,中的launchMode属性。 相关的代码中也有一些标志可以使用,比如我们想只启用一个实例,则可以使用 Intent.FLAG_ACTIVITY_REORDER_TO_FRONT 标志,这个标志表示:如果这个activity已经启动了,就不产生新的activity,而只是把这个activity实例加到栈顶来就可以了。
- Intent intent = new Intent(ReorderFour.this, ReorderTwo.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- startActivity(intent);
FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_RESET_TASK_IF_NEEDED FLAG_ACTIVITY_SINGLE_TOP
taskAffinity launchMode allowTaskReparenting clearTaskOnLaunch alwaysRetainTaskState finishOnTaskLaunch
本地服务 Local Service 用于应用程序内部。 它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服务。 用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
远程服务 Remote Service 用于android系统内部的应用程序之间。 它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用 Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。 可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
生命周期
使用context.startService() 启动Service是会会经历: context.startService() ->onCreate()- >onStart()->Service running context.stopService() | ->onDestroy() ->Service stop 如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。 stopService的时候直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。 所以调用startService的生命周期为:onCreate --> onStart(可多次调用) --> onDestroy
使用使用context.bindService()启动Service会经历: context.bindService()->onCreate()->onBind()->Service running onUnbind() -> onDestroy() ->Service stop onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。 所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。 在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。
- public class LocalService extends Service {
- private static final String TAG = "LocalService";
- @Override
- public IBinder onBind(Intent intent) {
- Log.i(TAG, "onBind");
- return null;
- }
- @Override
- public void onCreate() {
- Log.i(TAG, "onCreate");
- super.onCreate();
- }
- @Override
- public void onDestroy() {
- Log.i(TAG, "onDestroy");
- super.onDestroy();
- }
- @Override
- public void onStart(Intent intent, int startId) {
- Log.i(TAG, "onStart");
- super.onStart(intent, startId);
- }
- }
- public class ServiceActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.servicedemo);
- ((Button) findViewById(R.id.startLocalService)).setOnClickListener(
- new View.OnClickListener(){
- @Override
- public void onClick(View view) {
- // TODO Auto-generated method stub
- startService(new Intent("com.demo.SERVICE_DEMO"));
- }
- });
- ((Button) findViewById(R.id.stopLocalService)).setOnClickListener(
- new View.OnClickListener(){
- @Override
- public void onClick(View view) {
- // TODO Auto-generated method stub
- stopService(new Intent("com.demo.SERVICE_DEMO"));
- }
- });
- }
- }
- <service android:name=".LocalService">
- <intent-filter>
- <action android:name="com.demo.SERVICE_DEMO" />
- <category android:name="android.intent.category.default" />
- </intent-filter>
- </service>
- /**
- * This is an example of implementing an application service that runs locally
- * in the same process as the application. The {@link LocalServiceController}
- * and {@link LocalServiceBinding} classes show how to interact with the
- * service.
- *
- * <p>Notice the use of the {@link NotificationManager} when interesting things
- * happen in the service. This is generally how background services should
- * interact with the user, rather than doing something more disruptive such as
- * calling startActivity().
- */
- public class LocalService extends Service {
- private NotificationManager mNM;
- /**
- * 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);
- // We want this service to continue running until it is explicitly
- // stopped, so return sticky.
- return START_STICKY;
- }
- @Override
- public void onDestroy() {
- // Cancel the persistent notification.
- mNM.cancel(R.string.local_service_started);
- // 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);
- // Set the icon, scrolling text and timestamp
- Notification notification = new Notification(R.drawable.stat_sample, text,
- System.currentTimeMillis());
- // The PendingIntent to launch our activity if the user selects this notification
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
- new Intent(this, LocalServiceController.class), 0);
- // Set the info for the views that show in the notification panel.
- notification.setLatestEventInfo(this, getText(R.string.local_service_label),
- text, contentIntent);
- // Send the notification.
- // We use a layout id because it is a unique number. We use it later to cancel.
- mNM.notify(R.string.local_service_started, notification);
- }
- }
- /**
- * <p>Example of binding and unbinding to the {@link LocalService}.
- * This demonstrates the implementation of a service which the client will
- * bind to, receiving an object through which it can communicate with the service.</p>
- */
- public class LocalServiceBinding extends Activity {
- private boolean mIsBound;
- private LocalService mBoundService;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.local_service_binding);
- // Watch for button clicks.
- Button button = (Button)findViewById(R.id.bind);
- button.setOnClickListener(mBindListener);
- button = (Button)findViewById(R.id.unbind);
- button.setOnClickListener(mUnbindListener);
- }
- 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(LocalServiceBinding.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(LocalServiceBinding.this, R.string.local_service_disconnected,
- Toast.LENGTH_SHORT).show();
- }
- };
- private OnClickListener mBindListener = new OnClickListener() {
- public void onClick(View v) {
- // 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(LocalServiceBinding.this,
- LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
- mIsBound = true;
- }
- };
- private OnClickListener mUnbindListener = new OnClickListener() {
- public void onClick(View v) {
- if (mIsBound) {
- // Detach our existing connection.
- unbindService(mConnection);
- mIsBound = false;
- }
- }
- };
- }
- <service android:name=".app.LocalService" />
- public class SMSReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- // get data from SMS intent
- Bundle bundle = intent.getExtras();
- if (bundle != null){
- // get message by "pdus"
- Object[] objArray = (Object[]) bundle.get("pdus");
- // rebuild SMS
- SmsMessage[] messages = new SmsMessage[objArray.length];
- for (int i=0; i < objArray.length; i++){
- messages[i] = SmsMessage.createFromPdu((byte[])objArray[i]);
- StringBuilder str = new StringBuilder("from: ");
- str.append(messages[i].getDisplayOriginatingAddress());
- str.append("\nmessage:\n");
- str.append(messages[i].getDisplayMessageBody());
- Toast.makeText(context, str.toString(), Toast.LENGTH_LONG)
- .show();
- }
- }
- }
- }
- <receiver android:name=".SMSReceiver">
- <intent-filter>
- <action android:name="android.provider.Telephony.SMS_RECEIVED" />
- </intent-filter>
- </receiver>
- public class HelloDemo extends Activity {
- private BroadcastReceiver receiver;
- @Override
- protected void onStart() {
- super.onStart();
- receiver = new CallReceiver();
- registerReceiver(receiver, new IntentFilter("android.intent.action.PHONE_STATE"));
- }
- @Override
- protected void onStop() {
- unregisterReceiver(receiver);
- super.onStop();
- }
- }
- <uses-permission android:name="android.permission.RECEIVE_SMS" />
- public class CallReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- TelephonyManager teleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- switch(teleManager.getCallState()){
- case TelephonyManager.CALL_STATE_RINGING: //响铃
- Toast.makeText(context, "Ringing: " + intent.getStringExtra("incoming_number"), Toast.LENGTH_LONG).show();
- break;
- case TelephonyManager.CALL_STATE_OFFHOOK: //接听
- Toast.makeText(context, "OffHook: " + intent.getStringExtra("incoming_number"), Toast.LENGTH_LONG).show();
- break;
- case TelephonyManager.CALL_STATE_IDLE: //挂断
- Toast.makeText(m_context, "Idle: " + incomingNumber, Toast.LENGTH_LONG).show();
- break;
- }
- }
- }
- public class CallReceiver extends BroadcastReceiver {
- private Context m_context;
- @Override
- public void onReceive(Context context, Intent intent) {
- m_context = context;
- TelephonyManager teleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- teleManager.listen(new PhoneStateListener(){
- @Override
- public void onCallStateChanged(int state, String incomingNumber) {
- switch(state){
- case TelephonyManager.CALL_STATE_RINGING: //响铃
- Toast.makeText(m_context, "Ringing: " + incomingNumber, Toast.LENGTH_LONG)
- .show();
- break;
- case TelephonyManager.CALL_STATE_OFFHOOK: //接听
- Toast.makeText(m_context, "OffHook: " + incomingNumber, Toast.LENGTH_LONG)
- .show();
- break;
- case TelephonyManager.CALL_STATE_IDLE: //挂断
- Toast.makeText(m_context, "Idle: " + incomingNumber, Toast.LENGTH_LONG)
- .show();
- break;
- }
- }}, PhoneStateListener.LISTEN_CALL_STATE);
- }
- }
- <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
public Cursor query(Uri, String[], String, String[], String) 用于查询指定Uri的ContentProvider,返回一个Cursor public Uri insert(Uri, ContentValues) 用于添加数据到指定Uri的ContentProvider中 public int update(Uri, ContentValues, String, String[]) 用于更新指定Uri的ContentProvider中的数据 public int delete(Uri, String, String[]) 用于从指定Uri的ContentProvider中删除数据 public String getType(Uri) 用于返回指定的Uri中的数据的MIME类型
ContentResolver cr = getContentResolver(); ContentResolver提供的方法和ContentProvider提供的方法对应的有以下几个方法。 public Uri insert(Uri uri, ContentValues values) 用于添加数据到指定Uri的ContentProvider中。 public int delete(Uri uri, String selection, String[] selectionArgs) 用于从指定Uri的ContentProvider中删除数据。 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 用于更新指定Uri的ContentProvider中的数据。 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 用于查询指定Uri的ContentProvider。