偶然翻到一片文章,用两张图告诉你,为什么你的App会卡顿?,写得很好,跟着这篇文章学习后准备自己做个笔记,用作备忘。
activity可以说是android里面最重要的类,是界面的呈现者,也是和系统交互的沟通桥梁。对于这个类,我们肯定会有很多问题,比如以下:
如何响应用户的输入
界面如何显示
activity的视图结构是怎样
如何和系统交互
下面先从父类接口和成员变量,方法等方面简单分析下activity这个类。最后我们尝试回答上面的几个问题。
activity的重要成员变量
private Instrumentation mInstrumentation;
private IBinder mToken;
private Application mApplication;
private ComponentName mComponent;
/*package*/ ActivityInfo mActivityInfo;
/*package*/ ActivityThread mMainThread;
Activity mParent;
private Window mWindow;
private WindowManager mWindowManager;
final Handler mHandler = new Handler();
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
private Thread mUiThread;
以上是activity的一部分重要的成员变量,从成员变量的类型来看activity很复杂,不过我们挑着重要的看一下。
Instrumentation这个类是负责和系统的交互,不过隐藏在背后。
Application用来保存一些全局的应用数据,也是app程序开发的入口。
ComponentName这个就是四大组件,在使用adb启动activity,service,BroadcastReceiver等组件时需要带上-n 就表示要启动ComponentName。
ActivityInfo这个类主要用来保存activity的一些数据,比如主题,启动模式,权限等固定信息。
ActivityThread是我们app程序的主线程,即UI线程。
Window 用来管理呈现的窗口,和界面有关系。
WindowManager 负责管理窗口及显示的内容
每一个成员变量都不简单,o(╥﹏╥)o。
父类及接口
父类
Activity的直接父类是ContextThemeWrapper,这个类不太熟。先看这个类的父类也就是ContextWrapper,ContextWrapper的父类是我们平时接触最多的是Context,总算有点熟悉了。context可以认为是给应用提供了各种和系统交互的能力,因此重要的application,activity,service等都是其子类。context的详细介绍参见这篇文章:深入理解 Android 中的各种 Context。activity因此就具备了和系统交互的能力,包括和四大组件的交互,资源、文件、主题等方法。
接口
LayoutInflater.Factory2 : 布局创建相关的,接口只有一个方法。
public interface Factory2 extends Factory {
public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
}
Window.Callback: 负责用户输入交互的,因此activity就具备和用户交互的能力。
public interface Callback {
public boolean dispatchKeyEvent(KeyEvent event);
public boolean dispatchKeyShortcutEvent(KeyEvent event);
public boolean dispatchTouchEvent(MotionEvent event);
public boolean dispatchTrackballEvent(MotionEvent event);
public boolean dispatchGenericMotionEvent(MotionEvent event);
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event);
@Nullable
public View onCreatePanelView(int featureId);
public boolean onCreatePanelMenu(int featureId, Menu menu);
public boolean onPreparePanel(int featureId, View view, Menu menu);
public boolean onMenuOpened(int featureId, Menu menu);
public boolean onMenuItemSelected(int featureId, MenuItem item);
public void onWindowAttributesChanged(WindowManager.LayoutParams attrs);
public void onContentChanged();
public void onWindowFocusChanged(boolean hasFocus);
public void onAttachedToWindow();
public void onDetachedFromWindow();
public void onPanelClosed(int featureId, Menu menu);
public boolean onSearchRequested();
public boolean onSearchRequested(SearchEvent searchEvent);
@Nullable
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback);
@Nullable
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type);
public void onActionModeStarted(ActionMode mode);
public void onActionModeFinished(ActionMode mode);
default public void onProvideKeyboardShortcuts(
List<KeyboardShortcutGroup> data, @Nullable Menu menu, int deviceId) { };
default public void onPointerCaptureChanged(boolean hasCapture) { };
}
KeyEvent.Callback: 处理按键相关的交互。
public interface Callback {
boolean onKeyDown(int keyCode, KeyEvent event);
boolean onKeyLongPress(int keyCode, KeyEvent event);
boolean onKeyUp(int keyCode, KeyEvent event);
boolean onKeyMultiple(int keyCode, int count, KeyEvent event);
}
OnCreateContextMenuListener:菜单创建时的回调 ,不是很清楚 (¦3」∠)。
public interface OnCreateContextMenuListener {
void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo);
}
ComponentCallbacks2: 四大组件通用的回调,比如设置时的回调以及低内存时的操作。
public interface ComponentCallbacks2 {
void onConfigurationChanged(Configuration newConfig);
void onLowMemory();
void onTrimMemory(@TrimMemoryLevel int level);
}
Window.OnWindowDismissedCallback: window消失时的操作。
public interface OnWindowDismissedCallback {
void onWindowDismissed(boolean finishTask, boolean suppressWindowTransition);
}
WindowControllerCallback:不是很清楚这个什么时候回调 ε=(´ο`*)))。
public interface WindowControllerCallback {
void toggleFreeformWindowingMode() throws RemoteException;
void enterPictureInPictureModeIfPossible();
boolean isTaskRoot();
}
AutofillManager.AutofillClient: 自动填写相关的功能。
public interface AutofillClient {
void autofillClientAuthenticate(int authenticationId, IntentSender intent,
Intent fillInIntent);
void autofillClientResetableStateAvailable();
boolean autofillClientRequestShowFillUi(@NonNull View anchor, int width, int height,
@Nullable Rect virtualBounds, IAutofillWindowPresenter presenter);
void autofillClientDispatchUnhandledKey(@NonNull View anchor, @NonNull KeyEvent keyEvent);
boolean autofillClientRequestHideFillUi();
boolean autofillClientIsFillUiShowing();
@NonNull boolean[] autofillClientGetViewVisibility(@NonNull AutofillId[] autofillIds);
boolean autofillClientIsVisibleForAutofill();
boolean isDisablingEnterExitEventForAutofill();
@NonNull View[] autofillClientFindViewsByAutofillIdTraversal(
@NonNull AutofillId[] autofillIds);
@Nullable View autofillClientFindViewByAutofillIdTraversal(@NonNull AutofillId autofillId);
@Nullable View autofillClientFindViewByAccessibilityIdTraversal(int viewId, int windowId);
void autofillClientRunOnUiThread(Runnable action);
ComponentName autofillClientGetComponentName();
@Nullable IBinder autofillClientGetActivityToken();
boolean autofillClientIsCompatibilityModeEnabled();
@Nullable AutofillId autofillClientGetNextAutofillId();
}
activity继承自context这个类,具备了很多和系统交互的能力。然后还实现了一堆借口,因此也有了多个特定方面的能力。对于这么多接口,只能先有个概念,之后有需要再详细分析。
重要的方法
构造函数?
一般分析类的时候都是从构造方法开始,然后activity有点特殊,只有默认的构造方法。我们直接看下activity的创建,创建是在ActivityThread中,关键代码如下。
// ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
}
//Instrumentation.java
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
String pkg = intent != null && intent.getComponent() != null
? intent.getComponent().getPackageName() : null;
return getFactory(pkg).instantiateActivity(cl, className, intent);
}
//AppComponentFactory.java
public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
@Nullable Intent intent)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (Activity) cl.loadClass(className).newInstance();
}
可以看到activity的创建是通过反射的方式,其实application和service的创建也是通过反射创建。activity,application等属于android中特有的类,不仅仅是普通的类,创建的时候还需要上下文等信息,不知道这个是不是通过反射创建的原因?
attach
在activity实例创建出来后随即调用了attach方法。
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
enableAutofillCompatibilityIfNeeded();
}
在这个方法中给重要的成员变量赋值了。
todo
1 为什么是通过反射的方式创建activity?
为什么
get
1 提出问题,带着问题去学习
网友评论