
要启动一个新的Activity,我们可以通过调用Context中的startActivity来启动。像这样:
Intent intent = new Intent(this, ActivityDemoclass);
startActivity(intent); // ActivityDemo是需要启动的Activity类
通过上面的方法可以启动新的Activity了,但如果我要从当前的Activity中传递数据到新的Activity呢?很简单:Intent intent = new Intent(this,ActivityDemoclass);
Bundle bundle = new Bundle();
bundleputBoolean("bool_key", true);
intentputExtras(bundle);
startActivity(intent);
还有,有时候我们需要启动带返回值的Activity,简单的说就是需要新启动的Activity返回时将值传递给启动它的Activity,像这样:
Intent intent = new Intent(ActivityLifeDemothis,RevalueActivityclass);
startActivityForResult(intent, 0x1001);
ActivityLifeDemo是当前的Activity,启动RevalueActivity,我们在ActivityLifeDemo中需要获取RevalueActivity传回来的值。那么在RevalueActivity中就必须这样写:
Intent intent = new Intent();
intentputExtra("revalue_key","haha-revalueActivity");
setResult(0x1001, intent);
那么“revalue_key”值在哪里获取呢?必须重写onActivityResult方法,通过判断requestCode,来确定
if(requestCode==0x1001){
String str = datagetStringExtra("revalue_key");
Logi(TAG, "返回的值为:"+str);
}
activity可以 *** 作service了,我们还需要service能 *** 作activity。
我觉得可以有3中方式:
1直接把activity传给service,service通过activity实例随便 *** 作activity
2使用接口回调方式,activity实现相应的接口,service通过接口进行回调,比较灵活
3使用广播
使用广播是比较常见的方式,我们就不具体讲解了,下面我们介绍前面2中方法,具体看代码,用service更新seekbar。
我们的activity代码:
[html] view plain copy
package comhckbindservice;
import androidappActivity;
import androidcontentComponentName;
import androidcontentIntent;
import androidcontentServiceConnection;
import androidosBundle;
import androidosIBinder;
import androidutilLog;
import androidviewView;
import androidwidgetSeekBar;
import androidwidgetToast;
import comhckbindserviceMyServiceMyBuild;
public class MainActivity extends Activity {
private MyService myService; //我们自己的service
private SeekBar pBar; //模拟service更新进度条
private ConnectionService connectionService;
@Override
protected void onCreate(Bundle savedInstanceState) {
superonCreate(savedInstanceState);
setContentView(Rlayoutmain);
pBar = (SeekBar) findViewById(Ridseekbar);
connectionService=new ConnectionService();
}
public void startService(View view) { //绑定service
bindService(new Intent(this,MyServiceclass), connectionService, 1);
}
/
@author Administrator
实现service接口,用于service绑定时候,回调
/
class ConnectionService implements ServiceConnection
{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService=((MyBuild)service)getMyService(); //获取Myservice对象
/
直接把当前对象传给service,这样service就可以随心所欲的调用本activity的各种可用方法
/
myServicesetMainActivity(MainActivitythis); //把当前对象传递给myservice
/
使用一个接口来实现回调,这样比上面方法更加灵活,推荐
/
// myServicesetOnProgressBarListener(new UpdateProgressListener() {
//
// @Override
// public void updateBar(int size) {
// updateBar(size);
// }
// });
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
/
@param size
更新seekbar
/
public void updateBar(int size)
{
pBarsetProgress(size);
}
/
@param view
开始更新seekbar
/
public void startBar(View view) {
if (myService==null) {
ToastmakeText(this, "请先开始service", ToastLENGTH_LONG)show();
}
else {
myServicestartUpdateProgress();
}
}
/
@param view
停止更新seekbar
/
public void stopBar(View view) {
if (myService==null) {
ToastmakeText(this, "更新没有开始", ToastLENGTH_LONG)show();
}
else {
myServicestopUpdateProgress();
}
}
/
@param view
停止service
/
public void stopService(View view) {
myService=null;
unbindService(connectionService);
}
@Override
protected void onDestroy() {
superonDestroy();
try {
unbindService(connectionService);
} catch (Exception e) {
}
}
}
重要代码是onServiceConnected回调方法里面
myService=((MyBuild)service)getMyService(); //获取Myservice对象
获取service对象后,我们想怎么 *** 作它都行了,比如上面的,把activity实例直接通过它的方法传递过去,便于
service调用activity的各种方法。或者,设置传递一个回调接口对象过去,用户回调
service代码:
[html] view plain copy
package comhckbindservice;
import androidappService;
import androidcontentIntent;
import androidosBinder;
import androidosHandler;
import androidosIBinder;
import androidutilLog;
public class MyService extends Service{
private int size=0;
private UpdateProgress updateProgress;
private final long TIME=2000;
private boolean isUpdate=true;
private MainActivity activity;
private UpdateProgressListener listener;
@Override
public IBinder onBind(Intent intent) {
return new MyBuild();
}
@Override
public void onCreate() {
superonCreate();
updateProgress=new UpdateProgress();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return superonStartCommand(intent, flags, startId);
}
/
@author Administrator
线程用来改变seekbar进度的大小
/
class UpdateProgress implements Runnable
{
@Override
public void run() {
if (isUpdate) {
size+=10;
if (size>100) {
size=0;
}
handlersendEmptyMessage(0);
}
}
}
/
调用更新相应方法,更新进度条
/
Handler handler=new Handler()
{
public void handleMessage(androidosMessage msg) {
/
直接调用activity对象里面的方法
/
if (activity!=null) {
activityupdateBar(size);
}
/
使用接口回调
/
// if (listener!=null) {
// listenerupdateBar(size);
// }
handlerpostDelayed(updateProgress, TIME);
};
};
/
停止更新
/
public void stopUpdateProgress()
{
isUpdate=false;
}
/
开启更新
/
public void startUpdateProgress()
{
if (!isUpdate) {
handlerpost(updateProgress);
}
isUpdate=true;
}
public void onDestroy() {
isUpdate=false;
};
/
@param activity
初始化MainActivity对象
/
public void setMainActivity(MainActivity activity)
{
thisactivity=activity;
}
/
@param listener
初始化UpdateProgressListener对象
/
public void setOnProgressBarListener(UpdateProgressListener listener)
{
thislistener=listener;
}
/
@author Administrator
使用类部类,返回当前service的实例,用于activity,调用service的各种方法
/
class MyBuild extends Binder
{
public MyService getMyService()
{
return MyServicethis;
}
}
}
service里面最重要的就是,最下面我们的MyBuild类部类了,通过它的getMyService方法,获取service的实例
该类的实例实在onBind时候,我们返回给activity的。
接口:
[html] view plain copy
package comhckbindservice;
public interface UpdateProgressListener {
public void updateBar(int size);
}
一个简单接口,用于service回调activity
上面是使用 bindService来启动service的,那么如果我们使用startService启动service时候,上面的办法就不行了。
因为onBind不会执行,我们获取不到IBinder实例。这个时候,我们可以使用设计模式的观察者模式来处理。
普通Activity的启动就是通过调用startActivity方法启动一个新的Activity,总体流程如下图:
其中涉及到了两个进程,一个是App进程和AMS进程。整体的步骤是:
1启动者Activity向Instrumentation请求启动目标的Activity。
2 Instrumentation通过AMS在App进程的IBinder接口(IActivityManager)访问AMS,此时App进程会阻塞等待AMS的调用返回,采用的跨进程通信技术是AIDL。
3AMS会进行一系列的验证工作,如判断目标Activity实例是否存在、启动模式是什么、有没有在AndroidManifest中注册等等。
4当AMS验证结束后会通过ClinentLifeCycleManager发送事物给App进程,利用App进程在AMS进程的IBinder接口(IApplicationThread)访问App进程ApplicationThread,采用的跨进程通信方式是AIDL。
5ApplicationThread是ActivityThread的内部类,当ApplicationThread接受到来自AMS的事务后,会将事务直接转交给ActivityThread处理。
6ActivityThread通过Instrumentation利用类加载器(反射)进行实例的创建,同时利用Instrumentation回调目标Activity的生命周期。
介绍几个关键的类:
Instrumentation:Instrumentation 是 Activity 与外界联系的类(不是 Activity 本身的类都统称为外界)。目标 Activity 通过 Instrumentation 来请求启动,ActivityThread 通过 Instrumentation 来创建 Activity 和回调 Activity 的生命周期。
ActivityThread:每个应用程序只有一个唯一实例,负责对 Activity 创建的管理。ActivityThread 的内部类 ApplicationThread 只负责 App 进程和 AMS 进程的通信,将来自 AMS 的事务交给 ActivityThread 处理。
AMS,全称 ActivityManagerService,系统级服务,负责管理四大组件。
根Actvity就是我们点击手机桌面图标时,应用程序启动的第一个Activity。启动根Activity的流程其实和启动普通Activity的流程类似,只是启动根Activity时需要新建一个App进程。总体流程如下图:
其中涉及到四个进程分别是:Launcher进程、AMS进程、App进程、Zygote进程。
1点击桌面图标后,Launcher进程访问AMS进程请求启动目标Activity,采用的跨进程方式是AIDL。
2 AMS进程访问Zygote进程请求启动一个新的进程。采用的跨进程方式是Socket。
3 Zygote进程通过调用fork函数创建一个App进程。
4 App进程创建完成后,App进程访问AMS进程进行通知,采用的跨进程方式是AIDL。
5 AMS进程收到来自App进程的通知后,将启动Activity的 *** 作封装成事务,并将封装好的事务发送给App进程。
6 App进程接受到来自AMS进程的事务后,根据事务创建目标Activity,并回调目标Activity的生命周期。
本文主要是用来记录自己的学习笔记,看原文请移步: Activity 启动流程
相关源码:
调用 startActivity 或 startActivityForResult 来启动Activity。那么启动的Activity有两种情况:第一种是启动同进程内的Activity; 第二种是启动不同进程的根Activity,比如在桌面点击启动App,就是启动不同进程的Activity。这两种情况的Activity的启动流程大致相同,其流程大致是以下三个过程:
以下逐一讲解这三大过程:
下图是调用进程向system_server进程发起请求的过程:
startActivityForResult方法继续调用 InstrumentationexecStartActivity 方法。而Instrumentation类主要用来监控应用程序和系统的交互。
下图是ATMS处理startActivity过程,并回调启动进程的ApplicationThread
ATMS startActivity:
ATMS类通过一系列方法调用最终来到 startActivityAsUser 的方法,该方法先检查调用进程的权限,然后通过 getActivityStartController()obtainStarter 创建 ActivityStarter 类,并把参数设置到 ActivityStarterRequest 类中,最后执行 ActivityStarterexecute() 方法。
ActivityStarter准备堆栈
在 ActivityStarter executeRequest 方法中先做一系列的检查,包括调用进程的检查、Intent的检查、权限的检查、向PKMS获取启动Activity的ActivityInfo等信息,然后调用 startActivityUnchecked 方法开始对要启动的Activity做堆栈管理。
在 startActivityInner 方法中,根据启动模式计算出flag,在根据flag等条件启动的Activity的ActivityRecord是加入现有的Task栈中,还是创建新Task栈。为Activity准备好堆栈后,调用 RootWindowContainerresumeFocusedStacksTopActivities 方法
ActivityStack对栈的管理:
对于启动Activity对应的 ActivityStack 来说,是管理其栈中Activity的显示逻辑。而后继续调用 ActivityStackSupervisorstartSpecificActivity
ActivityStackSupervisor检查启动进程和回调ApplicationThread
在ActivityStackSupervisor中先检查要启动Activity的进程是否存在,不存在则创建进程,存在则调用 realStartActivityLocked ,realStartActivityLocked方法通过事务给回调 ApplicationThread scheduleTransaction 方法。
下图为ActivityThread启动Activity过程的时序图:
ApplicationThread类绕了一大圈,最后调用在ATMS阶段设置的ClientTransaction的CallBack的execute方法,也就是 LaunchActivityItem execute 方法,此方法创建一个 ActivityClientRecord 对象,然后调用 ActivityThread handleLaunchActivity 开启真正的Actvity启动。
真正启动Activity:
在Android中每个界面都是一个Activity,切换界面 *** 作其实是多个不同Activity之间的实例化 *** 作。在Android中Activity的启动模式决定了Activity的启动运行方式。
Android总Activity的启动模式分为四种:
Activity启动模式设置:
<activity android:name="MainActivity" android:launchMode="standard" />
Activity的四种启动模式:
1 standard
模式启动模式,每次激活Activity时都会创建Activity,并放入任务栈中。
2 singleTop
如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。
3 singleTask
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
4 singleInstance
在一个新栈中创建该Activity实例,并让多个应用共享改栈中的该Activity实例。一旦改模式的Activity的实例存在于某个栈中,任何应用再激活改Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。
其中standard是系统默认的启动模式。
下面通过实例来演示standard的运行机制:
1 private TextView text_show;
2 private Button btn_mode;
3
4 @Override
5 public void onCreate(Bundle savedInstanceState) {
6 superonCreate(savedInstanceState);
7 setContentView(Rlayoutactivity_main);
8
9 text_show = (TextView) thisfindViewById(Ridtext_show);
10
11 text_showsetText(thistoString());
12
13 btn_mode = (Button) thisfindViewById(Ridbtn_mode);
14
15 }
16
//按钮单击事件
17 public void LaunchStandard(View v){
18 startActivity(new Intent(this,MainActivityclass));
19
20 text_showsetText(thistoString());
21 }
我们一般写的比较简单的方法就是starActivity(new Intent(context,Aclass))这种启动的方式很简单,就是一个从当前界面跳转到下一个activity界面。
首先我们先要说一个问题,当你有d窗信息,或者通知栏里面出现了通知,然后你点击进去,不知道你有没有在意,APP会在五秒钟之后打开,当然,有的不会 大多数还是会的。现在我们就说一下这个问题
在谷歌的 Android API Guides 中,特意提醒开发者不要在后台启动 activity,包括在 Service 和 BroadcastReceiver 中,这样的设计是为了避免在用户毫不知情的情况下突然中断用户正在进行的工作
就是当通过 home 键将当前 activity 置于后台时,任何在后台startActivity 的 *** 作都将会延迟 5 秒,除非该应用获取了 "androidpermissionSTOP_APP_SWITCHES" 权限但是这个权限是系统级别的权限
解决方法:
不能够用传统的startActivity来启动Activity
Intent intent = new Intent(context, Aclass);
intentsetFlags(IntentFLAG_ACTIVITY_NEW_TASK);
contextstartActivity(intent);
而是要用以下形式来启动Activity:
Intent intent = new Intent(context, Aclass);
intentsetFlags(IntentFLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent =
PendingIntentgetActivity(context, 0, intent, 0);
try {
pendingIntentsend();
} catch (PendingIntentCanceledException e) {
eprintStackTrace();
}
OK,这种方式启动activity,一般是用在有后台任务的时候
starActivityforResult(),里面有两个参数,一个是intent,还有一个是requestcode,当你启动下一个界面的然后又关闭的时候,会得到一个返回值,这个返回值就是这个requestcode,你需要做的就是通过onActivityforResult()方法去进行对这个requestcode进行判断,处理好相应的逻辑
这个文章是我睡前写的,手机上面实在不好打字
以上就是关于如何启动一个activity涉及到哪些方法全部的内容,包括:如何启动一个activity涉及到哪些方法、service怎么得到绑定的activity实例、Activity启动流程笔记等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)