电商网站费用,购物网站开发简介,八戒电影在线观看免费7,备案域名出售平台文章目录 前言活动概述活动间的通信活动的生命周期活动的启动模式 服务概述启动和停止服务活动和服务间的通信服务的生命周期使用前台服务使用IntentService 前言
众所周知#xff0c;Android的四大组件包括#xff1a;活动#xff08;Activity#xff09;、服务#xff… 文章目录 前言活动概述活动间的通信活动的生命周期活动的启动模式 服务概述启动和停止服务活动和服务间的通信服务的生命周期使用前台服务使用IntentService 前言
众所周知Android的四大组件包括活动Activity、服务Service、广播接收器Broadcast Receiver、内容提供器Content Provider。本文先来介绍一下活动以及服务广播接收器与内容提供器在下一篇文章介绍。
活动
概述
活动是用户进行操作的可视化界面它为用户提供了一个完成指令的窗口在App中几乎所有可见的的内容都要依托Activity所以Activity是开发中使用最频繁的一个组件。在这我们主要来讲解一下活动间的通信、活动的生命周期、活动的启动模式。
活动间的通信
Intent通常用于启动活动、启动服务以及发送广播等场景这里就来介绍一下启动活动。
显示Intent
Intent intentnew Intent(this,AnotherActivity.class);
startActivity(intent);向下一个活动传递数据
例如此时我们有FirstActivity和SecondActivity两个活动
在FirstActivity
String data你好;
Intent intentnew Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra(extra_data,data);//extra_data相当于一个标识在下一个活动我们也是通过extra_data来接收数据
startActivity(intent);这样我们就将“你好”这个数据传递到了SecondActivity接下来只需要在SecondActivity取出来即可
在SecondActivity
Intent intentgetIntent();
String dataintent.getStringExtra(extra_data);字符串类型数据使用getStringExtra()方法接收整型数据使用getIntExtra()方法接收布尔型数据使用getBooleanExtra()方法接收
返回数据给上一个活动
当我们从一个活动退出返回到上一个活动时如果我们想传递数据给上一个活动就可以使用到这里。
在启动活动时我们不再使用startActivity()方法而是使用startActivityForResult()方法这个方法期望我们启动的活动在销毁时可以返回一个结果给上一个活动。
在FirstActivity
Intent intentnew Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);// 设置请求码为1在SecondActivity
Intent intentnew Intent();
intent.putExtra(data_return,你好);
setResult(RESULT_OK,intent);
finish();接着我们需要在FirstActivity中定义一个onActivityResult()方法来接收返回的数据
Override
protected void onActivityResult(int requestCode,int resultCode,Intent data){ //requestCode是我们在启动活动时传入的请求码switch(requestCode){case 1:if(resultCodeRESULT_OK){String returnDatadata.getStringExtra(data_return);}break;default:}
}另外需要注意的是如果我们是通过点击按钮返回FirstActivity那么按钮的点击事件就和上面SecondActivity的代码那样即可但如果我们是通过按下Back键返回到FirstActivity那我们就要在SecondActivity重写onBackPressed方法了
Override
public void onBackPressed(){Intent intentnew Intent();intent.putExtra(data_return,你好);setResult(RESULT_OK,intent);finish();
}启动活动的最佳写法
在原本的启动活动的写法中当我们要向启动的活动传数据时我们可能并不知道传什么类型的数据此时我们就可以换一种启动活动的写法。
在SecondActivity中定义一个actionStart()方法
public static void actionStart(Context context,String data1,String data2){Intent intentnew Intent(context,SecondActivity.class);intent.putExtra(data_1,data1);intent.putExtra(data_2,data2);context.startActivity(intent);
}这样一来我们就清楚了要启动SecondActivity要传递两个String类型的数据接着在FirstActivity中启动SecondActivity
SecondActivity.actionStart(FirstActivity.this,data1,data2);活动的生命周期
Android使用栈来管理活动。
活动状态
运行状态活动位于栈顶时。暂停状态活动不再处于栈顶但却仍然可见如一个对话框形式的活动A出现在一个活动B上面时对话框并没有占据整个屏幕此时活动B就处于暂停状态。停止状态不处于栈顶且完全不可见的时候。此时系统仍会保存相应的状态和成员变量。但当其他地方需要内存时处于停止状态的活动可能被回收。销毁状态从栈中被移除了。
活动的生存期
Activity中定义了7个回调方法覆盖了活动声明周期的每一个环节
onCreate()在活动第一次创建时被调用完成一些初始化操作加载布局、绑定事件等onStart()活动由不可见变为可见时调用onResume()活动准备好和用户进行交互时调用此时活动一定处于栈顶onPause()在系统准备去启动或恢复另一个活动时调用。通常在这个方法中将一些消耗CPU的资源释放保留一些关键数据。onStop()在活动完全不可见时调用。其与onPause()方法的区别在于当启动的活动是对话框形式的onPause()会执行onStop()不会执行onDestory()在活动被销毁前调用调用后活动的状态将变为销毁状态onRestart()在活动由停止状态变为运行状态之前调用也就是活动重新启动了。
可以将活动分为三种生存期
完整生存期onCreate()方法与onDestroy()方法之间经历的。在onCreate()完成各种初始化操作在onDestroy()完成释放内存操作。可见生存期onStart()方法与onStop()方法间经历的。我们可以通过这两个方法对资源经行合理管理如在onStart()对资源经行加载在onStop()对资源经行释放。前台生存期onResume()方法和onPause()方法间经历的此时活动总是处于运行状态活动位于返回栈的栈顶常在这里与用户进行交互。
活动的启动模式
在AndroidManifest.xml中的activity/activity标签通过android:launchMode来指定
standard活动默认的启动模式在该模式下系统不会在乎这个活动在栈中是否已经存在每次启动该活动都会创建一个新的实例。singleTop在启动这个活动时如果发现返回栈中栈顶已经是该活动了直接去使用它不再去新建一个活动实例。singleTask在启动这个活动时每次去检查返回栈中是否存在活动的实例存在则直接使用不存在则创建新的活动实例。singleInstance指定为该模式的活动会启动一个新的返回栈来管理这个活动。这样做可以实现其他程序和我们这个程序共享这个活动实例不管哪个程序来访问这个活动都公用同一个返回栈。
服务
概述
服务是实现程序后台运行的解决方案允许用户在切换到另一个程序界面的情况下本程序依然能够正常运行即切换到后台例如我们听音乐时将音乐软件切到后台。但需要注意的是切到后台此时进程并未结束如果进程被杀掉依赖于该进程的服务也会停止。
服务并不会自动开启线程所有代码都是默认在主线程运行的但这样可能出现主线程被阻塞的情况所以我们需要在服务内部手动创建子线程并在这里面执行具体任务本文后面也会讲解在子线程处理服务的耗时逻辑所以我们需要了解一下Android多线程编程的知识可以看看这篇博客Android多线程编程。
启动和停止服务
在此之前我们先来创建出一个服务右击项目包名-New-Service-Service在弹出的窗口有两个可勾选的属性Exported表示是否允许当前程序被其他程序访问Enabled表示是否启用这个服务这里我们全部勾选上。
将创建好的服务添加一些代码如下所示
public class MyService extends Service {public MyService() {}Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.throw new UnsupportedOperationException(Not yet implemented);}//服务创建时调用Overridepublic void onCreate(){super.onCreate();Log.d(MyService,onCreate executed);}//服务启动时调用Overridepublic int onStartCommand(Intent intent,int flags,int startId){Log.d(MyService,onStartCommand executed);return super.onStartCommand(intent,flags,startId);}//服务销毁时调用Overridepublic void onDestroy(){super.onDestroy();Log.d(MyService,onDestroy executed);}
}通常情况如果我们希望服务一旦启动就立刻去执行某个动作就可以将逻辑写在onStartCommand()方法中。当服务被销毁时在onDestroy()方法中去回收不再使用的资源。还有一点就是onCreate()只有在服务被第一次创建是才会调用onStartCommand()在每次启动服务时都会调用。
服务的启动和停止也是借助Intent来实现的如下所示
public class MainActivity extends AppCompatActivity implements View.OnClickListener {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button start(Button) findViewById(R.id.start);Button stop(Button) findViewById(R.id.stop);start.setOnClickListener(this);stop.setOnClickListener(this);}Overridepublic void onClick(View view) {switch (view.getId()){case R.id.start:Intent startIntentnew Intent(this, MyService.class);//启动服务startService(startIntent);break;case R.id.stop:Intent stopIntentnew Intent(this, MyService.class);//暂停服务stopService(stopIntent);break;default:break;}}
}其中startService()方法和stopService()方法都是定义在Context类中的可以直接调用。当然我们也可以在MyService中来自行停止服务只需在任意地方调用stopSelf()即可。
接着我们就可以通过点击按钮来测试了如果没问题的话点击开启服务按钮控制台会打印onCreate executed、onStartCommand executed点击暂停服务按钮控制台会打印onDestroy executed
活动和服务间的通信
还记得我们在创建服务时有一个onBind()方法吗它允许我们在活动中去控制服务将服务与活动联系起来。
例如我们想在MyService中实现一个下载功能模拟然后希望在活动中可以决定什么时候开始下载以及可以查看下载进度要想实现这个功能就需要我们创建一个专门的Binder对象这里就DownloadBinder了来对下载功能进行管理了。MyService中代码如下
public class MyService extends Service {private DownLoadBinder mBindernew DownLoadBinder();class DownLoadBinder extends Binder{public void startDownload(){Log.d(MainActivity,startDownload executed);}public int getProcess(){Log.d(MainActivity,getProcess executed);return 0;}}Overridepublic IBinder onBind(Intent intent) {return mBinder;}......
}在MyService服务中我们新建了一个DownloadBinder类让它继承自Binder并在它的内部实现了开始下载和查看下载进度的方法当然只是模拟一下。接着在MyService中创建了DownloadBinder的实例mBinder最后别忘了在onBind()方法中将mBinder返回。
接下来我们就可以在活动中去写绑定服务和解绑服务的逻辑了
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private MyService.DownLoadBinder downLoadBinder;private ServiceConnection connectionnew ServiceConnection() {//绑定成功时调用Overridepublic void onServiceConnected(ComponentName name, IBinder service) {//在这获取了downLoadBinder对象我就可以在任意地方去调用downLoadBinder对象的任意方法了downLoadBinder(MyService.DownLoadBinder) service;//开始下载downLoadBinder.startDownload();//获取进度downLoadBinder.getProcess();}//活动与服务断开连接时调用Overridepublic void onServiceDisconnected(ComponentName componentName) {}};Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);...Button bindService(Button) findViewById(R.id.bind_service);Button unbindService(Button) findViewById(R.id.unbind_service);bindService.setOnClickListener(this);unbindService.setOnClickListener(this);}Overridepublic void onClick(View view) {switch (view.getId()){...case R.id.bind_service:Intent bindIntentnew Intent(this, MyService.class);//绑定服务bindService(bindIntent,connection,BIND_AUTO_CREATE);break;case R.id.unbind_service://解绑服务unbindService(connection);default:break;}}
}我们创建出一个ServiceConnection匿名类在里面重写了onServiceConnection()方法和onServiceDisconnected()方法分别在活动与服务成功绑定时和断开连接时调用。尤其注意onServiceConnected()这个方法在这里面我们通过向下转型获得了DownloadBinder的实例那我们是不是就可以在活动中去随意调用服务中的方法了呢这样一来我们的活动与服务不就紧密连接起来了。
当然真正让我们的活动与服务绑定起来的代码是bindService(bindIntent,connection,BIND_AUTO_CREATE);第二个参数是匿名类ServiceConnection的实例BIND_AUTO_CREATE表示活动与服务绑定之后自动创建服务这样只会使MyService中的onCreate()方法得到执行onStartCommand()不执行。
最后任何一个服务在整个应用程序都是通用的即MyService可以与任意活动绑定绑定完获得的是相同的DownloadBinder实例。
服务的生命周期
我们前面在MyService中编写的onCreate()、onStartCommand()、onBind()、onDestory()等方法都是在服务的生命周期中可能回调的方法一旦调用Context的startService()方法服务就会启动起来并回调onStartCommand()方法如果这个服务之前还没被创建过onCreate()方法会先于onStartCommand()方法执行。之后服务会一直保持运行状态直到stopService()或stopSelf()方法被调用。需要注意的是虽然每调用一次startService()方法onStartCommand()方法就会执行一次但始终服务只存在一个实例只需调用一次stopService()或stopSelf()方法服务就会停止。还可以调用Context的bindService()方法来获取一个服务的持久连接这时会调用服务中的onBind()方法如果这个服务之前还没被创建过onCreate()方法会先于onBind()方法执行。调用方活动获得onBind()方法返回的IBinder即可进行通信了。当调用了startService()方法又调用了stopService()方法服务中的onDestroy()方法才会执行同样的调用了bindService()方法又调用了unbindService()方法服务中的onDestroy()方法才会执行那当同时调用了startService()方法和bindService()方法要咋样服务中的onDestroy()方法才会执行呢答案是同时调用stopService()方法和unbindService()方法。
使用前台服务
由于服务的优先级较低当系统出现内存不足时就有可能回收掉正在后台运行的服务如果你不想服务因为内存不足被回收可以使用前台服务。当然有时候你可能并不是为了防止服务被回收才使用前台服务的有些特殊需求必须使用前台服务来完成。
前台服务和后台服务最大的区别就是前台服务会有一个正在运行的图标在系统的状态栏显示下拉状态栏就可以看到更加详细的信息类似于通知的效果。
创建一个前台服务如下在onCreate()方法中 Overridepublic void onCreate(){super.onCreate();Log.d(MyService,OnCreate);//创建notificationManager对通知进行管理NotificationManager notificationManager getSystemService(NotificationManager.class);if(Build.VERSION.SDK_INT Build.VERSION_CODES.O){String channelId channelId;//通知渠道的标识符CharSequence channelName ...;//通知渠道的位置String channelDescription ...;//通知渠道的描述//设置通知渠道的级别int importance NotificationManager.IMPORTANCE_DEFAULT;//创建通知渠道NotificationChannel notificationChannel new NotificationChannel(channelId,channelName,importance);notificationChannel.setDescription(channelDescription);//在系统中注册消息notificationManager.createNotificationChannel(notificationChannel);}Intent intent new Intent(this,MainActivity.class);PendingIntent pi PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);//创建通知Notification notification new NotificationCompat.Builder(this,001).setContentTitle(标题).setContentText(内容).setWhen(System.currentTimeMillis()).setSmallIcon(R.mipmap.ic_launcher).setContentIntent(pi).build();//显示通知startForeground(1,notification);}调用startForeground()方法可以让你的MyService变成一个前台服务并在系统状态栏显示出来。
使用IntentService
以上我们的所有代码都是运行在主线程的如果直接在服务里去做一些耗时逻辑就非常容易出现ANRApplication Not Responding的情况。
这里我们先来了解一下什么是ANRANR是指在主线程上执行耗时操作或阻塞操作时无法响应用户输入或与系统交互的情况。当发生ANR时应用程序会被系统视为未响应的并可能导致应用崩溃或被用户强制关闭。
这时我们就需要用到Android多线程编程的技术了我们应该在服务的每个具体的方法里开启一个子线程在这里去处理那些耗时逻辑所以一个标准的服务就可以写成以下形式同时让服务执行完毕自动停下来
public class MyService extends Service {...Overridepublic int onStartCommand(Intent intent,int flags,int startId){new Thread(new Runnable(){Overridepublic void run(){//具体逻辑stopSelf();}}).start();return super.onStartCommand(intent,flags,startId);}
}为了简化上述步骤Android提供了一个IntentService类这个类允许我们简单地创建一个异步的、会自动停止的服务。
首先创建一个MyIntentService继承自IntentService记得在AndroidManifest.xml文件中注册这个服务
public class MyIntentService extends IntentService {public MyIntentService() {//调用父类的有参构造super(MyIntentService);}Overrideprotected void onHandleIntent(Nullable Intent intent) {//打印当前线程idLog.d(MyIntentService,Thread id is Thread.currentThread().getId());}Overridepublic void onDestroy(){super.onDestroy();Log.d(MyIntentService,onDestroy executed);}
}在这个类中我们实现了onHandleIntent()这个方法在这个方法里面我们可以去实现那些耗时逻辑并且不用担心ANR问题因为这个方法是在子线程中运行的通过打印线程id来验证这里我们还重写了onDestroy()方法来验证服务执行完会不会自动停止。
在MainActivity中 Button startIntentService(Button) findViewById(R.id.start_intent_service);startIntentService.setOnClickListener(this);Overridepublic void onClick(View view) {switch (view.getId()){case R.id.start_intent_service:Log.d(MainActivity,Thread id is Thread.currentThread().getId());Intent intentServicenew Intent(this, MyIntentService.class);startService(intentService);break;default:break;}}在这通过打印主线程id来与onHandleIntent()方法中线程的id做对比点击按钮后你会发现 根据打印结果来看首先MyIntentService的onHandleIntent()方法确实是在子线程中执行的其次服务执行完后会自动停止。