//GET方式获取百度主页内容
NSString *url = [NSString stringWithFormat:@"http://www.baidu.com"];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager.responseSerializer setAcceptableContentTypes:[NSSet setWithObjects:@"text/html", nil]];
[manager GET:url parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSString *result = [[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(@"%@",result);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"%@",[error localizedDescription]);
}];
OC-MBProgressHUD使用
//默认菊花加文本,加背景模糊
hud.mode = MBProgressHUDModeIndeterminate;
hud.label.text=@"加载中...";
hud.backgroundView.style = MBProgressHUDBackgroundStyleSolidColor;
hud.contentColor = [UIColor whiteColor];//文字和菊花的颜色
hud.backgroundView.color = [UIColor blackColor];
hud.backgroundView.alpha = 0.5f;
hud.bezelView.backgroundColor = [UIColor blackColor];//菊花背景颜色
//纯文本
hud.label.text = @"操作成功";
hud.mode = MBProgressHUDModeText;
hud.contentColor = [UIColor whiteColor];//文字的颜色
hud.bezelView.backgroundColor = [UIColor blackColor];//背景颜色
//自定义图标加文本
hud.label.text=@"删除成功";
hud.mode=MBProgressHUDModeCustomView;
hud.contentColor = [UIColor whiteColor];//文字的颜色
hud.bezelView.backgroundColor = [UIColor blackColor];//背景颜色
hud.customView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"succes_pic_yes"]];
OC-对话框
//显示弹出框列表选择
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Title"
message:@"This is an Sheet."
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction* cancelAction = [UIAlertAction
actionWithTitle:@"取消"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
//响应事件
NSLog(@"action = %@", action);
}];
UIAlertAction* deleteAction = [UIAlertAction
actionWithTitle:@"删除" style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
//响应事件
NSLog(@"action = %@", action);
}];
UIAlertAction* saveAction = [UIAlertAction actionWithTitle:@"保存" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//响应事件
NSLog(@"action = %@", action);
}];
[alert addAction:saveAction];
[alert addAction:cancelAction];
[alert addAction:deleteAction];
[self presentViewController:alert animated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Title"
message:@"This is an alert."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction
actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//响应事件
NSLog(@"OK");
}];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//响应事件
NSLog(@"CANCEL");
}];
[alert addAction:defaultAction];
[alert addAction:cancelAction];
[self presentViewController:alert animated:YES completion:nil];
OC-UILabel点击事件
laGetVoiceCode.userInteractionEnabled = YES;
UITapGestureRecognizer *getVoiceCode =
[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(getVoiceCode:)];
[_laGetVoiceCode addGestureRecognizer:getVoiceCode];
//获取语音验证码
-(void) getVoiceCode:(UITapGestureRecognizer *) recognizer{
UILabel *label =(UILabel*) recognizer.view;
NSLog(@"%@被点击了",label.text);
}
launcher 启动Main
Launcher通过AMS来启动Main,Launcher、AMS、Main位于3个不同的进程中。
通过Binder实现进程间通信
用户通过点击Launcher向AMS发送一个启动Main的请求
AMS收到Launcher请求,记录Main信息。然后出一个请求让Binder进入中止状态。
Launcher进入中止状态,然后告诉AMS我已经中止了,你去启动Main吧
AMS去启动Main,怎么启动呢?Main是通过Main所在的进程创建的,但是AMS发现Main依附的应用程序进程还不存在,没法创建Main,
AMS只能先去负责创建Main的进程
Main的进程创建完成后,AMS会收到一个进程间请求告诉他Main的进程已经创建了
AMS收到进程间通信请求,知道Main的进程已经创建了,就把Main的信息给了Main的进程,让他去创建Main。
用户-校长
Launcher-优秀教师代表
Launcher图标-每一个学生
Main-B同学
AMS-政教处主任
Process-班主任
新学期开始,九年级的学生们都来到学校操场,然后在各个班的指定区域区域坐下,老师们的位置在前面,学生们的位置在老师后面。
优秀教师L代表站在台上,讲着上次考试中一些同学取得优异成绩,脸上十分满足。
校长突然走过来,指着最后一排的M同学问优秀教师L:"那是哪个班的?在底下也不老实!让他上台"。
优秀教师L代表很无奈,我也不认识这个同学啊。他向政教处主任A打了一个电话,让那个同学上来。
政教处主任A接到电话后,记录了一下M的位置,然后说你先别演讲了。
优秀教师L从台上下来,然后告诉政教处主任我已经下来,你把M同学叫上来吧。
政教处主任A准备让M同学上台,可是他也不认识M,他只能去找M的班主任B,可是班主任B这个时候不在,也就没法通知M同学。
于是政教处主任A只能打电话让班主任B快点过来。
班主任B收到电话后,马上往操场赶,到了后马上打电话告诉政教处主任A我到了。
政教处主任A收到班主任B的电话,把M同学的位置,穿的衣服等信息告诉了班主任B,让B去把M同学叫上台。
ActivityStackSupervisor-resolveActivity
查看resolveActivity方法
ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
ProfilerInfo profilerInfo, int userId) {
// Collect information about the target of the Intent.
ActivityInfo aInfo;
try {
ResolveInfo rInfo =
AppGlobals.getPackageManager().resolveIntent(
intent, resolvedType,
PackageManager.MATCH_DEFAULT_ONLY
| ActivityManagerService.STOCK_PM_FLAGS, userId);
aInfo = rInfo != null ? rInfo.activityInfo : null;
} catch (RemoteException e) {
aInfo = null;
}
if (aInfo != null) {
// Store the found target back into the intent, because now that
// we have it we never want to do this again. For example, if the
// user navigates back to this point in the history, we should
// always restart the exact same activity.
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
// Don't debug things in the system process
if ((startFlags&ActivityManager.START_FLAG_DEBUG) != 0) {
if (!aInfo.processName.equals("system")) {
mService.setDebugApp(aInfo.processName, true, false);
}
}
if ((startFlags&ActivityManager.START_FLAG_OPENGL_TRACES) != 0) {
if (!aInfo.processName.equals("system")) {
mService.setOpenGlTraceApp(aInfo.applicationInfo, aInfo.processName);
}
}
if (profilerInfo != null) {
if (!aInfo.processName.equals("system")) {
mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
}
}
}
return aInfo;
}
ActivityInfo-resolveActivity
###源码位置android.content.pm.ActivityInfo.java
public class ActivityInfo extends ComponentInfo
implements Parcelable {}
继承自ComponentInfo,实现了Parcelable接口,可以序列化
/**
* Information you can retrieve about a particular application
* activity or receiver. This corresponds to information collected
* from the AndroidManifest.xml's <activity> and
* <receiver> tags.
*/
它就是从Activity或者Receiver得到的信息。这对应着从AndroidManifest.xml的<activiy>标签和
<receiver>标签得到的信息。
####问题1->”既然从Receiver收集到的信息也能是ActivityInfo,难道Receiver属于Activity?
小米权限测试
##AndPermission+AppOpsManager
AppOpsCode
API25:
/**
* Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
* allowed to perform the given operation.
*/
public static final int MODE_ALLOWED = 0;
/**
* Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
* not allowed to perform the given operation, and this attempt should
* <em>silently fail</em> (it should not cause the app to crash).
*/
public static final int MODE_IGNORED = 1;
/**
* Result from {@link #checkOpNoThrow}, {@link #noteOpNoThrow}, {@link #startOpNoThrow}: the
* given caller is not allowed to perform the given operation, and this attempt should
* cause it to have a fatal error, typically a {@link SecurityException}.
*/
public static final int MODE_ERRORED = 2;
/**
* Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller should
* use its default security check. This mode is not normally used; it should only be used
* with appop permissions, and callers must explicitly check for it and deal with it.
*/
public static final int MODE_DEFAULT = 3;
小米MAX2 7.1.1 25
储存权限
禁止时
AndPermission返回false
op->android:read_external_storage
AppOpsCode->0
AndPermission申请权限弹不出来,没有失败或者成功回调
允许时
AndPermission返回true
op->android:read_external_storage
AppOpsCode->0
流程正确
询问时
AndPermission返回false
op->android:read_external_storage
AppOpsCode->0
AndPermission申请权限可以弹出来,拒绝时走onfailed方法
拒绝一次后,
AndPermission返回false
op->android:read_external_storage
AppOpsCode->0
AndPermission申请权限可以弹出来,带有不再提示的选项,拒绝时走onfailed方法
拒绝2次后,这次选中了不再提示,权限管理中心直接变为禁止状态,和禁止状态一样。
AndPermission返回false
op->android:read_external_storage
AppOpsCode->0
AndPermission申请权限弹不出来,没有失败或者成功回调
位置权限
禁止时
AndPermission返回false
op->android:read_external_storage
AppOpsCode->0
AndPermission申请权限弹不出来,没有失败或者成功回调
允许时
AndPermission返回true
op->android:read_external_storage
AppOpsCode->0
流程正确
询问时
AndPermission返回false
op->android:read_external_storage
AppOpsCode->0
AndPermission申请权限可以弹出来,拒绝时走onfailed方法
拒绝一次后,
AndPermission返回false
op->android:read_external_storage
AppOpsCode->0
AndPermission申请权限可以弹出来,带有不再提示的选项,拒绝时走onfailed方法
拒绝2次后,这次选中了不再提示,权限管理中心直接变为禁止状态,和禁止状态一样。
AndPermission返回false
op->android:read_external_storage
AppOpsCode->0
AndPermission申请权限弹不出来,没有失败或者成功回调
小米2 5.0.2 21
储存权限
不需要申请
位置权限
允许时
AndPermission返回true
AppOpsCode->0
流程正确
禁止时
AndPermission返回true
AppOpsCode->1
此时请求权限,返回请求成功,实际没有
询问时
AndPermission返回true
AppOpsCode->4
此时请求权限,返回请求成功,实际没有
Instrumentation.callActivityOnCreate
查看callActivityOnCreate方法
/**
* Perform calling of an activity's {@link Activity#onCreate}
* method. The default implementation simply calls through to that method.
*
* @param activity The activity being created.
* @param icicle The previously frozen state (or null) to pass through to onCreate().
*/
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
转到activity.performCreate();
final void performCreate(Bundle icicle) {
onCreate(icicle);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
转到onCreate(icicle);
/**
* Called when the activity is starting. This is where most initialization
* should go: calling {@link #setContentView(int)} to inflate the
* activity's UI, using {@link #findViewById} to programmatically interact
* with widgets in the UI, calling
* {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve
* cursors for data being displayed, etc.
*
* <p>You can call {@link #finish} from within this function, in
* which case onDestroy() will be immediately called without any of the rest
* of the activity lifecycle ({@link #onStart}, {@link #onResume},
* {@link #onPause}, etc) executing.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @param savedInstanceState If the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
* recently supplied in {@link #onSaveInstanceState}. <b><i>Note: Otherwise it is null.</i></b>
*
* @see #onStart
* @see #onSaveInstanceState
* @see #onRestoreInstanceState
* @see #onPostCreate
*/
@MainThread
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
if (mLastNonConfigurationInstances != null) {
mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
}
if (mActivityInfo.parentActivityName != null) {
if (mActionBar == null) {
mEnableDefaultActionBarUp = true;
} else {
mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
}
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
}
mFragments.dispatchCreate();
getApplication().dispatchActivityCreated(this, savedInstanceState);
if (mVoiceInteractor != null) {
mVoiceInteractor.attachActivity(this);
}
mCalled = true;
}
到这里就走到了Activity的onCreate,过程中涉及到的代码很多,留作慢慢研究。
ActivityThread-scheduleLaunchActivity
查看scheduleLaunchActivity方法
// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
重点sendMessage(H.LAUNCH_ACTIVITY, r);
发送除了一个H.LAUNCH_ACTIVITY的消息,这个消息被
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
}
}
}
转到handleLaunchActivity方法
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
// Initialize before creating the activity
WindowManagerGlobal.initialize();
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
if (!r.activity.mFinished && r.startsNotResumed) {
// The activity manager actually wants this one to start out
// paused, because it needs to be visible but isn't in the
// foreground. We accomplish this by going through the
// normal startup (because activities expect to go through
// onResume() the first time they run, before their window
// is displayed), and then pausing it. However, in this case
// we do -not- need to do the full pause cycle (of freezing
// and such) because the activity manager assumes it can just
// retain the current state it has.
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
// We need to keep around the original state, in case
// we need to be created again. But we only do this
// for pre-Honeycomb apps, which always save their state
// when pausing, so we can not have them save their state
// when restarting from a paused state. For HC and later,
// we want to (and can) let the state be saved as the normal
// part of stopping the activity.
if (r.isPreHoneycomb()) {
r.state = oldState;
}
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPause()");
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to pause activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.paused = true;
}
} else {
// If there was an error, for any reason, tell the activity
// manager to stop us.
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
// Ignore
}
}
}
转到performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
重点
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
###转到Instrumentation.callActivityOnCreate