Android开发艺术探索

README

《Android开发艺术探索》

任玉刚

共15章


第一章 Activity的生命周期和启动模式

四大组件:Activity/Service/Broadcast Receiver/Content Provider
六大布局:RelativeLayout/LinearLayout/FrameLayout/TableLayout/AbsoluteLayout/GridLayout
一个信使:Intent
可见界面:Activity/Toast/Snack/Dialog/Window/Notification
Activity的典型生命周期:onCreate() [onStart() [onResume() onPause() 前台可见] onStop() 后台可见] onDestroy() onRestart()
视图结构:View Parent->ViewGroup-View/ViewGroup树 Activity->Window(PhoneWindow)->DecorView->TitleView/ContentView(setContentView()/setSupportActionBar())
Activity启动:startActivity()->Instrumentation(Binder)->ActivityManagerService(ActivityStack)-ActivityThread
注:ActivityA启动ActivityB,ActivityA的onPause()先于ActivityB的onCreate()执行
Activity的异常生命周期:onSaveInstanceState()->onStop()-onStart()->onRestoreInstanceState() 委托思想
Activity优先级:前台可见 后台可见 不可见
Activity不重建生命周期:onConfigurationChanged() android:configChanges = "orientation|keyboardHidden" //使系统不重建Activity
Activity启动模式:android:launchMode="standard/singTop/singTask/singInstance"  onNewIntent()
A task is a stack of activities
Context:Application/Activity/Service 只有Activity有TaskStack
taskAffinity配合singleTask/allowTaskReparenting使用 当allowTaskReparenting="true"时AppA启动AppB的ActivityX会转移到AppB的TaskStack中
Activity的Flags:FLAG_ACTIVITY_NEW_TASK/FLAG_ACTIVITY_SINGLE_TOP/FLAG_ACTIVITY_CLEAR_TOP/FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
IntentFilter的匹配规则:action/category/data
action的匹配规则(String):必须有 Intent只有一个 IntentFilter可多个 有一个匹配即可
category的匹配规则(String):可没有 Intent可多个 IntentFilter可多个 Intent完全匹配
data的匹配规则(mimeType+URI):必须有 Intent只有一个 IntentFilter可多个 有一个匹配即可
显示调用/隐示调用
隐示判断:PackageManager的resolveActivity()和queryIntentActivities() 或则 Intent的resolveActivity() MATCH_DEFAULT_ONLY


第二章 IPC机制

IPC(Inter-Process Communication):Bundle 文件共享 AIDL Messenger ContentProvider Socket
ANR Application Not Responding
Binder
Android中的进程:android:process 或则JNI Native folk
android:process=":remote" 私有进程
android:process="com.gh.light.remote" 全局进程 ShareUID
问题:静态成员和单例模式完全失效/线程同步机制完全失效/SharedPreferences的可靠性下降/Application会多次创建
Serializable接口:空接口 private static final long serialVersionUID = 1L; 序列化反序列化:ObjectOutputStream/ObjectInputStream  静态变量和transient不参与序列化
Parcelable接口:
public class User implements Parcelable {
    public int userId;
    public String userName;
    public boolean isMale;
    
    public Book book;
    
    public User(int userId, String userName, boolean isMale) {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;
    }
    
    /*内容描述*/
    public int describeContents() {
        return 0;
    }
    
    /*序列化*/
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(userId);
        out.writeString(userName);
        out.writeInt(isMale ? 1 : 0);
        out.writeParcelable(book, 0);
    }
    
    /*反序列化*/
    public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
        public User createFromParcel(Parcel in) {
            return new User(in);
        }
        
        public User[] newArray(int size) {
            return new User[size];
        }
    };
    
    private User(Parcel in) {
        userId = in.readInt();
        userName = in.readString();
        isMale = in.readInt() == 1;
        book = in.readParcelable(Thread.currentThread().getContextClassLoader());
    }
}
Serializable适用于序列化对象到存储设备和网络传输
Binder implements IBinder /dev/binder
public interface IBookManager extends android.os.IInterface
IBookManager文件详解:
DESCRIPTOR Binder的唯一标识,一般为Binder的类名
asInterface(android.os.IBinder obj) 转化Binder为AIDL
asBinder() 返回当前Binder
public Boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) 运行中服务端 code可以标志请求方法 如果返回false则客户端请求失败
Proxy#getBookList() Proxy#addBook()
linkToDeath() unlinkToDeath()
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
    public void binderDied() {
        if(mBookManager == null) {
            return;
        }
        mBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
        mBookManager = null;
    }
};
mService = IBookManager.Stub.asInterface(binder);
binder.linkToDeath(mDeathRecipient, 0);
IPC方式:
Bundle/文件共享/SharedPreferences

Messenger信使:Message 服务端 客户端
服务端:
public class MessengerService extends Service {
    private static final String TAG = "MessengerService";
    private static class MessengerHandler extends Handler {
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case MSG_FROM_CLIENT:
                    System.out.println(msg.getData().getString("msg"));
                    Messenger client = msg.replyTo;
                    ... ...
                    client.send(msg);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
    
    private final Messenger mMessenger = new Messenger(new MessengerHandler());
    
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}
客户端:
private Messenger mService;
// public void onServiceConnected(ComponentName className, IBinder service)
mService = new Messenger(service);
Message msg = Message.obtain(null, MSG_FROM_CLIENT);
Bundle data = new Bundle();
data.putString("msg", "Hello, this is client.");
msg.setData(data);
msg.replyTo = mGetReplyMessenger;//同服务端创建一个Messenger
mService.send(msg);

AIDL(Android Interface Defination Language)
步骤:
1 创建.aidl文件 byte short int long float double boolean char String CharSequence List(ArrayList) Map(HashMap) Parcelable AIDL
  Book.java 同名Book.aidl parcelable Book;
  in out inout 不支持静态常量
2 服务端实现 CopyOnWriteArrayList/ConcurrentHashMap
  private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
  private Binder mBinder = new IBookManager.Stub() {};
3 客户端实现
  IBookManager bookManager = IBookManager.Stub.asInterface(service);  
  观察者模式 RemoteCallbackList
 
  binderDied()肯onServiceDisconnected()区别 不可访问UI
 
ContentProvider
CRUD(insert() delete() update() query()) + onCreate() getType()
ContentResolver MediaStore SQLite
注册:
<provider
    android:name".provider.BookProvider"
    android:authorities="com.study.mm.book.provider"
    android:permission="com.study.PROVIDER"
    android:progress=":provider" />
访问:
Uri uri = Uri.parse("content://com.study.mm.book.provider");
getContentResolver().query(uri, null, null, null, null);

五大存储:SharedPreferences/File/SQLite/ContentProvider/Network

SQLiteOpenHelper Constructors() onCreate() onUpgrade()
UriMatcher

Socket TCP/UDP

Binder连接池
interface ISecurityCenter {
    String encrypt(String content);
    String decrypt(String password);
}

interface ICompute {
    int add(int a, int b);
}

public class SecurityCenterImpl extends ISecurityCenter.Stub

public class ComputeImpl extends ICompute.Stub

interface IBinderPool {
    IBinder queryBinder(int binderCode);
}

Service里返回:new BinderPool.BinderPoolImpl();


第三章 View的事件体系

View是一个矩形区域
ViewParent->ViewGroup->(View/ViewGroup) View树
Activity->Window(PhoneWindow)->DecorView(TittleView+ContentView) setSupportActionBar() setContentView()
View坐标系:左上角为0点 右下为正方向 getLeft()/getRight()/getTop()/getBottom() left right top bottom x y translationX translationY

MotionEvent ACTION_DOWN ACTION_MOVE ACTION_UP getX() getY() (相对于当前View) getRawX() getRawY() (相对于手机屏幕)

TouchSlop ViewConfiguration.get(getContext()).getScaledTouchSlop()

VelocityTracker
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = velocityTracker.getXVelocity();
velocityTracker.clear();velocityTracker.recycle();

GestureDetector
GestureDetector mGestureDetector = new GestureDetector(this);
mGestureDetector.setIsLongPressEnable(false);
boolean consume = mGestureDetector.onTouchEvent(event); return consume;
实现:OnGesureListener OnDoubleTapListener的方法

Scroller弹性滑动
scrollTo() scrollBy()
Scroller scroller = new Scroller(mContext);

View的滑动:
使用scrollTo()/scrollBy() 操作简单 适合对View内容的滑动
使用动画 操作简单 适用于没有交互的View和实现复杂的动画效果
改变布局参数 操作复杂 适用于有交互的View
使用Scroller进行弹性滑动

View事件的分发处理(委托思想):先分发 再拦截 谁拦截 谁处理 不处理 就回调 处理完 就结束
public boolean dispatchTouchEvent(MotionEvent ev)
public boolean onInterceptTouchEvent(MotionEvent ev)
public boolean onTouchEvent(MotionEvent ev)

互动冲突:外部拦截法 内部拦截法


第十二章 Bitmap的加载和Cache

OOM(Out Of Memory)
16M Bitmap
LruCache 内存缓存
DisLruCache 磁盘缓存
LRU(Least Recently Used)最近最少使用
ListView GridView RecyclerView

Bitmap
BitmapFactory decodeFile/decodeResource/decodeStream/decodeByteArray
BitmapFactory.Options inJustDecodeBounds inSampleSize outWidth outHeight 2
public Bitmap compressBitmap(Resources res, int id, int requireWidth, int requireHeight) {
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inJustDecodeBounds = true;
    BitmapFactory.decodeResources(res, id, opts);
    int outWidth = opts.outWidth;
    int outHeight = opts.outHeight;
    int inSampleSize = 1;
    while(outWidth > requireWidth || outHeight >requireHeight) {
        inSampleSize *= 2;
        outWidth /= 2;
        outHeight /= 2;
    }
    opts.inSampleSize = inSampleSize;
    opts.inJustDecodeBounds = false;
    return BitmapFactory.decodeResources(res, id, opts);
}

LruCache Android 3.1 support-v4 Android 2.2 LinkedHashMap
强引用:不被GC
软引用:内存不足GC
弱引用:随时GC
int maxSize = (int)(Runtime.getRuntime().maxMemory() / 8);
LruCache<String, Bitmap> mLruCache = new LruCache<String, Bitmap>(maxSize) {
    protected int sizeOf(String key, Bitmap bitmap) {
        return bitmap.getRowBytes() *  bitmap.getHeight();
    }
    create()
    entryRemoved()
};
mLruCache.get(key);
mLruCache.put(key, bitmap);
mLruCache.remove(key);

/sdcard/Android/data/package_name/cache
/data/data/package_name/cache

File directory = getCacheDirectory(context, "bitmap");
if (!directory.exists()) {
    directory.mkdir();
}
int version = getAppVersion(context);
int maxSize = 10 * 1024 * 1024;
mDiskLruCache = DiskLruCache.open(directory, version, 1, maxSize);

private int getAppVersion(Context context) {
    String packageName = context.getPackageName();
    PackageManager packageManager = context.getPackageManager();
    try {
        PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
        return packageInfo.versionCode;
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
    return 1;
}

private File getCacheDirectory(Context context, String uniqueName) {
    String cachePath;
    String state = Environment.getExternalStorageState();
    boolean isRemovable = Environment.isExternalStorageRemovable();
    if (TextUtils.equals(state, Environment.MEDIA_MOUNTED) || !isRemovable) {
        cachePath = context.getExternalCacheDir().toString();
    } else {
        cachePath = context.getCacheDir().toString();
    }
    return new File(cachePath + File.separator + uniqueName);
}

private String getKey(String src) {
    String key;
    try {
        MessageDigest digest = MessageDigest.getInstance("MD5");
        digest.update(src.getBytes());
        byte[] bytes = digest.digest();
        key = bytes2HexString(bytes);
    } catch (NoSuchAlgorithmException e) {
        key = String.valueOf(src.hashCode());
    }
    return key;
}

private String bytes2HexString(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < bytes.length; i++) {
        String string = Integer.toHexString(0xFF & bytes[i]);
        if (string.length() == 1) {
            sb.append('0');
        }
        sb.append(string);
    }
    return sb.toString();
}

public void put(String key) {
    try {
        DiskLruCache.Editor editor = mDiskLruCache.edit(key);
        OutputStream os = editor.newOutputStream(0);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void get(String key) {
    try {
        DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
        InputStream is = snapshot.getInputStream(0);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public boolean remove(String key) {
    try {
        return mDiskLruCache.remove(key);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

public void delete() {
    try {
        mDiskLruCache.delete();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public long size() {
    return mDiskLruCache.size();
}

public void close() {
    try {
        mDiskLruCache.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

ImageLoader 先从内存缓存加载,再从磁盘缓存加载,最后从网络加载写入缓存

优化卡顿:
不在getView()执行耗时操作
控制异步任务的执行频率
开启硬件加速android:hardwareAccelerated="true"


第十四章 JNI和NDK编程

JNI Java Native Interface
NDK Native Development Kit
代码保护
提高效率
引用开源库
libc libm libz liblog

static {
    System.loadLibrary("libHelloJNI");
}

public native static String print(String name);
public static native String print(String name);
native public static String print(String name);

jstring Java_com_study_hellojni_MainActivity_print(JNIEnv* env, jobject thiz, jstring name);
#include<jni.h>
env JVM指针 obj调用该方法的对象

Application.mk Android.mk jni目录
APP_ABI := armeabi

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := helloJNI
LOCAL_SRC_FILES := hello.cpp
include $(BUILD_SHARED_LIBRARY)

jbyte jshort jint jlong jfloat jdouble jboolean jchar
jclass jobject jsarray jsring void jobjectArray jbooleanArray ... jthrowable

Java call C/C++
C/C++ call Java


第十五章 Android性能优化

OOM SOF ANR

布局优化
减少层级
include merge ViewStub
16ms 60fps

内存优化
ListView Bitmap
MAT
Debug.startMethodTracing();
Debug.stopMethodTracing();

猜你喜欢

转载自blog.csdn.net/zhaicaixiansheng/article/details/52995334