拓展

硬件加速

Android 屏幕绘制机制及硬件加速

Android硬件加速小结

冷启动和热启动

Android冷启动和热启动

多进程编程

原文链接:巧用Android多进程,微信,微博等主流App都在用

一、进程与线程

进程:是程序运行的实例,是系统进行资源分配和调度的一个独立单位,它包括独立的地址空间,资源以及1个或多个线程。
线程:可以看成是轻量级的进程,是CPU调度和分派的基本单位。

区别

1.调度

从上面的定义可以看出一个是调度和分派的基本单位,一个是拥有资源的基本单位。

2.共享地址空间,资源

进程拥有各自独立的地址空间,资源,所以共享复杂,需要用IPC,同步简单; 线程共享所属进程的资源,共享简单,但同步复杂,要通过加锁等措施。

3.占用内存,cpu

进程占用内存多,切换复杂,CPU利用率低; 线程占用内存少,切换简单,CPU利用率高。

4.相互影响

进程间不会相互影响; 一个线程挂掉会导致整个进程挂掉。

二、Android应用内多进程的介绍

正常情况下,一个apk启动后只会运行在一个进程中,其进程名为AndroidManifest.xml文件中指定的应用包名,所有的基本组件都会在这个进程中运行。但是如果需要将某些组件(如Service、Activity等)运行在单独的进程中,就需要用到android:process属性了。我们可以为android的基础组件指定process属性来指定它们运行在指定进程中。
好处

1、我们知道Android系统对每个应用进程的内存占用是有限制的,而且占用内存越大的进程,通常被系统杀死的可能性越大。让一个组件运行在单独的进程中,可以减少主进程所占用的内存,降低被系统杀死的概率。

2、如果子进程因为某种原因崩溃了,不会直接导致主程序的崩溃,可以降低我们程序的崩溃率。

3、即使主进程退出了,我们的子进程仍然可以继续工作,假设子进程是推送服务,在主进程退出的情况下,仍然能够保证用户可以收到推送消息。

缺陷

1、Application的多次重建

如果你在项目启动的时候就启动一些如百度地图的进程,你会发现Application onCreate 的打印出现了两次,而且pid的值也是不一样的。

public class MyApplication extends Application {  
    public static final String TAG = "viclee";  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        int pid = android.os.Process.myPid();  
        Log.d(TAG, "MyApplication onCreate");  
        Log.d(TAG, "MyApplication pid is " + pid);  
    }  
} 

2、静态成员的失效。

设置了process属性后,产生了两个隔离的内存空间,一个内存空间里值的修改并不会影响到另外一个内存空间。所以就算是静态成员也是两个不同的成员值。

3、文件共享问题。

多进程情况下会出现两个进程在同一时刻访问同一个数据库文件的情况。这就可能造成资源的竞争访问,导致诸如数据库损坏、数据丢失等。在多线程的情况下我们有锁机制控制资源的共享,但是在多进程中比较难,虽然有文件锁、排队等机制,但是在Android里很难实现。解决办法就是多进程的时候不并发访问同一个文件,比如子进程涉及到操作数据库,就可以考虑调用主进程进行数据库的操作。

4、断点调试问题。

调试就是跟踪程序运行过程中的堆栈信息,由于每个进程都有自己独立的内存空间和各自的堆栈,无法实现在不同的进程间调试。不过可以通过下面的方式实现:调试时去掉AndroidManifest.xml中android:process标签,这样保证调试状态下是在同一进程中,堆栈信息是连贯的。待调试完成后,再将标签复原。

二、Android应用内多进程的实现

只需要添加 android:process 的属性即可,属性名可以自定义,相同的属性名的进程在同一个里面运行。

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="com.example.processtest"  
    android:versionCode="1"  
    android:versionName="1.0" >  

    <uses-sdk  
        android:minSdkVersion="8"  
        android:targetSdkVersion="19" />  

    <application  
        android:name="com.example.processtest.MyApplication"  
        android:icon="@drawable/ic_launcher"  
        android:label="@string/app_name">  
        <activity  
            android:name=".ProcessTestActivity"  
            android:label="@string/app_name" >  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  

                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  

        <service  
            android:name=".ProcessTestService"  
            android:process=":remote">  
        </service>  
    </application>  

</manifest>

5.Android 锁屏&解锁&开屏监听

必须动态注册才可以监听到

  • 锁屏广播Action

Intent.ACTION_SCREEN_OFF

  • 解锁广播Action

Intent.ACTION_SCREEN_ON

  • 开屏广播Action

Intent.ACTION_USER_PRESENT

  • 广播ScreenBroadcastReceiver
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

import com.example.util.LogUtil;

/**
 * @author master
 * @date 2018/1/23
 */

public class ScreenBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        LogUtil.e("广播Action = " + action);
        if (action.equals(Intent.ACTION_SCREEN_OFF)) {
            LogUtil.e("锁屏");
        } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
            LogUtil.e("解锁");
        }else if(action.equals(Intent.ACTION_USER_PRESENT)){
            LogUtil.e("开屏");
        }
    }
}

注册广播(建议放在Service中注册)

       ScreenBroadcastReceiver screenBroadcastReceiver = new ScreenBroadcastReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_USER_PRESENT);
        getApplicationContext().registerReceiver(screenBroadcastReceiver, filter);

Android Service dump使用

Android Service dump使用

Android ANR分析详解

Android ANR分析详解

android ANR、traces文件获取及实例分析

Android 性能分析

Android性能分析之 Profiler

Android横竖屏切换时不销毁activity

首先在Mainifest.xml的Activity元素中加入android:configChanges="orientation|keyboardHidden"属性

<activity android:name=".FileBrowser"
          android:label="@string/app_name"
          android:configChanges="orientation|keyboardHidden">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

加入这条属性的含义是,应用程序将会处理屏幕方向和键盘状态(推出或合上)信息的改动。但对于其他的设备配置信息的改动则会由Android系统来处理(销毁当前Activity,然后重启一个新的Activity实例)。

那么,现在还需要在java代码的activity子类中加入配置信息改动的处理代码。这个也很简单

/**
 * onConfigurationChanged
 * the package:android.content.res.Configuration.
 * @param newConfig, The new device configuration.
 * 当设备配置信息有改动(比如屏幕方向的改变,实体键盘的推开或合上等)时,
 * 并且如果此时有activity正在运行,系统会调用这个函数。
 * 注意:onConfigurationChanged只会监测应用程序在AnroidMainifest.xml中通过
 * android:configChanges="xxxx"指定的配置类型的改动;
 * 而对于其他配置的更改,则系统会onDestroy()当前Activity,然后重启一个新的Activity实例。
 */
@Override
public void onConfigurationChanged(Configuration newConfig) {    
    super.onConfigurationChanged(newConfig);
    // 检测屏幕的方向:纵向或横向
    if (this.getResources().getConfiguration().orientation 
            == Configuration.ORIENTATION_LANDSCAPE) {
        //当前为横屏, 在此处添加额外的处理代码
    }
    else if (this.getResources().getConfiguration().orientation 
            == Configuration.ORIENTATION_PORTRAIT) {
        //当前为竖屏, 在此处添加额外的处理代码
    }
    //检测实体键盘的状态:推出或者合上    
    if (newConfig.hardKeyboardHidden 
            == Configuration.HARDKEYBOARDHIDDEN_NO){ 
        //实体键盘处于推出状态,在此处添加额外的处理代码
    } 
    else if (newConfig.hardKeyboardHidden
            == Configuration.HARDKEYBOARDHIDDEN_YES){ 
        //实体键盘处于合上状态,在此处添加额外的处理代码
    }
}

同时在java文件中加上 import android.content.res.Configuration。(或者自动导入)
这样就OK了,屏幕方向改变时,应用程序的显示界面也会随着改动,而不是被销毁!

扩展补充:

Activity中还有一属性和屏幕方向有关:

<activity 
   . . .
      android:screenOrientation=["unspecified" | "user" | "behind" |
                                 "landscape" | "portrait" |
                                 "sensor" | "nosensor"]
    . . .
</activity>

比如,在Mainifest.xml的Activity元素中增加这么一个属性:

android:screenOrientation="portrait"

则无论手机如何变动,拥有这个属性的activity都将是竖屏显示。

android:screenOrientation="landscape“,为横屏显示。

这里提一个小知识,Anroid模 拟器中,快捷键"ctrl+F11"可以实现转屏。

分类: Android

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注