Android单元测试

摘要:
Android提供了上面的多个测试类,可以允许我们对于单个方法、Activity、Service、Application等多个对象进行测试,单元测试可以很方便的让我们对代码进行测试,并且方便对重构后的代码进行检查。本篇将简要的讲解如何对Android中的对象进行测试。在Application中添加:配置文件代码一览:˂?

Android单元测试第1张

Android提供了上面的多个测试类,可以允许我们对于单个方法、Activity、Service、Application等多个对象进行测试,单元测试可以很方便的让我们对代码进行测试,并且方便对重构后的代码进行检查。本篇将简要的讲解如何对Android中的对象进行测试。

一、准备工作

首先在manifest.xml中添加权限和相关配置代码。

在Application外添加:

    <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
    <instrumentation  
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.kale.androidtest" />  

com.kale.androidtest是包名,意思是被测类所在的包名。

在Application中添加:

 <uses-library android:name="android.test.runner" />

配置文件代码一览:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.kale.androidtest"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
    <instrumentation  
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.kale.androidtest" />  
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />
    <application
        android:name="com.kale.androidtest.MyApplication"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <uses-library android:name="android.test.runner" />  
        <activity
            android:name=".MyActivity"
            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="com.kale.androidtest.MyService"/>
    </application>
</manifest>

注意:下面写的测试的方法一定要是public的,不然会报错!

二、测试与Android运行环境无关的方法

2.1InstrumentationTestCase

当你要测试与Android环境无关的方法时,推荐继承InstrumentationTestCase来进行测试。比如下面的比大小的方法就很适合做这样的测试。

    public static int getMax(int a, intb) {
        return a >= b ?a : b;
    }

得到版本号的代码因为涉及到了Context所以和android运行的环境有关,我们必须要传入一个上下文(context)对象,这时继承InstrumentationTestCase就没有办法进行测试了。

    /**取得当前应用的版本号
     * @paramcontext
     * @return
     */
    public staticString getVersionName(Context context) {
        try{
            PackageInfo manager = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            returnmanager.versionName;
        } catch(NameNotFoundException e) {
            return "Unknown";
        }
    }

那么是不是用它就不能对activity这样的东西进行测试了呢?也不是,我们仍旧可以用它来测试Activity,前题是要通过代码初始化对象,但因为它的子类可以针对Activity进行完善的测试,所以我们一般不用它来做测试activity的工作。第二节中,先给出了一个简单的demo,然后给出用它测试activity的demo。

2.2 举例

测试的目标类——MyUtils:

packagecom.kale.androidtest;
importandroid.content.Context;
importandroid.content.pm.PackageInfo;
importandroid.content.pm.PackageManager.NameNotFoundException;
public classMyUtils {
    public static int getMax(int a, intb) {
        return a >= b ?a : b;
    }
}

测试类——MySimpleTest:

packagecom.kale.androidtest.test;
importcom.kale.androidtest.MyUtils;
importandroid.test.InstrumentationTestCase;
public class MySimpleTest extendsInstrumentationTestCase  {
    public voidtestGetMax(){
        int max = MyUtils.getMax(1, 3);
        assertEquals(3, max);
    }
}

附:测试Activity

activity的代码就不贴了,里面有个editText,这里的测试也是简单的例子,表示它可以用来测试activity,例子没有任何实际意义。

packagecom.kale.androidtest.test;
importandroid.content.Intent;
importandroid.os.SystemClock;
importandroid.test.InstrumentationTestCase;
importandroid.widget.EditText;
importcom.kale.androidtest.MyActivity;
/**
 * @author:Jack Tony
 * @description  :
 * @web: http://www.oschina.net/question/54100_27061
 * @date  :2015年2月19日
 */
public class MySampleTest2 extendsInstrumentationTestCase {
    MyActivity mActivity;
    EditText mEditText;
    @Override
    protected void setUp() throwsException {
        //用intent启动一个activity
        Intent intent = newIntent();
        intent.setClassName("com.kale.androidtest", MyActivity.class.getName());
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mActivity =(MyActivity) getInstrumentation().startActivitySync(intent);
    }
    /**
     * @description 测试是否初始化完成
     *
     */
    public voidtestInit() {
        mEditText =mActivity.getEditText();
        assertNotNull(mActivity);
        assertNotNull(mEditText);
    }
    /**
     * @description 测试得到activity中editText中的文字
     *
     */
    public voidtestGetText() {
        mEditText =mActivity.getEditText();
        String text =mEditText.getText().toString();
        assertEquals("", text);
    }
    /**
     * @description 测试设置文字的方法
     *
     */
    public voidtestSetText() {
        mEditText =mActivity.getEditText();
        //在主线程中设置文字
        getInstrumentation().runOnMainSync(newRunnable() {
            @Override
            public voidrun() {
                mEditText.setText("kale");
            }
        });
        //暂停1500ms
        SystemClock.sleep(1000);
        assertEquals("kale", mEditText.getText().toString());
    }
    /**
     * 垃圾清理与资源回收
     * 
     * @seeandroid.test.InstrumentationTestCase#tearDown()
     */
    @Override
    protected voidtearDown() {
        mActivity.finish();
        try{
            super.tearDown();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

三、测试Application

3.1 ApplicationTestCase

首先我们来看看如何测试一个application,application是全局的一个对象,android提供了一个ApplicationTestCase来测试application。继承这个类后可以调用它自身的方法来构造和初始化一个application,得到的这个application就是我们要测试的application,接着我们就能测试它的公有方法了。这里注意,测试的代码和application的代码运行在不同的线程中,所以如果涉及到必须主线程才能进行的操作,比如更新UI等,就需要把代码传递到主线程中进行测试了。

3.2 待测试的Application

packagecom.kale.androidtest;
importandroid.app.Application;
public class MyApplication extendsApplication{
    @Override
    public voidonCreate() {
        //TODO 自动生成的方法存根
        super.onCreate();
    }
    publicString getTestString() {
        return "kale";
    }
}

3.3 测试代码

测试的代码中有两个重要的方法:createApplication()和getApplication(),通过建立一个application的方法来初始化application,通过得到application的方法来获得要测试的application。

注意:测试类的构造方法,必须是无参数的

    /*
     * 注意:构造函数不能这么写,否则会找不到类
     * @web :http://www.educity.cn/wenda/164209.html
     * 
     * public MyApplicationTest(Class<MyApplication> applicationClass) {
     *     super(applicationClass); 
     * }
     */
    //调用父类构造函数,且构造函中传递的参数为被测试的类
    publicMyApplicationTest() {
        super(MyApplication.class);
    }

在测试的类中我们初始化了application,之后测试了application中的一个获取字符串的方法,代码如下:

packagecom.kale.androidtest.test;
importandroid.test.ApplicationTestCase;
importcom.kale.androidtest.MyApplication;
/**
 * @author:Jack Tony
 * @description  :
 * @web: http://blog.csdn.net/stevenhu_223/article/details/8298858
 * @date  :2015年2月19日
 */
public class MyApplicationTest extends ApplicationTestCase<MyApplication>{
    privateMyApplication application;
    /*
     * 注意:构造函数不能这么写,否则会找不到类
     * @web :http://www.educity.cn/wenda/164209.html
     * 
     * public MyApplicationTest(Class<MyApplication> applicationClass) {
     *     super(applicationClass); 
     * }
     */
    //调用父类构造函数,且构造函中传递的参数为被测试的类
    publicMyApplicationTest() {
        super(MyApplication.class);
    }
    /*
     * 初始化application
     * @throws Exception
     */
    @Override
    protected void setUp() throwsException {
        super.setUp();
        //获取application之前必须调用的方法
createApplication();
        //获取待测试的FxAndroidApplication
        application =getApplication();
    }
    public voidtestGetString() {
        String realStr =application.getTestString();
        assertEquals("kale", realStr);
    }
}

四、测试Activity

4.1 要测试的activity

activity的布局文件很简单,有textview,edittext,button组成,相互独立,看效果就知道了。

Android单元测试第2张

布局文件的代码:

Android单元测试第3张Android单元测试第4张
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >
    <TextView
        android:id="@+id/test_textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/hello_world" />
    <Button
        android:id="@+id/test_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="90dp"
        android:text="Button" />
    <EditText
        android:id="@+id/test_editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/test_textView"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="79dp"
        android:ems="10" >
        <requestFocus />
    </EditText>
</RelativeLayout>
View Code

Activity代码

activity在onCreat()中初始化了控件,给button添加了一个监听器,button按下后设置textview的文字。

packagecom.kale.androidtest;
public class MyActivity extendsActivity {
    privateTextView testTv;
    privateEditText testEt;
    @Override
    protected voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }
    private voidinitView() {
        testEt =(EditText)findViewById(R.id.test_editText);
        testTv =(TextView)findViewById(R.id.test_textView);
        Button testBtn =(Button)findViewById(R.id.test_button);
        testBtn.setOnClickListener(newOnClickListener() {
            @Override
            public voidonClick(View v) {
                testTv.setText("kale");
            }
        });
    }
    /**
     * @description 得到textview中的text
     *
     * @return
     */
    publicString getText() {
        returntestTv.getText().toString();
    }
    /**
     * @description 不想修改本例中的editText的可见范围,但有需要在测试时得到这个控件,所以就get一下
     *
     * @return
     */
    publicEditText getEditText() {
        returntestEt;
    }
    /**
     * @description 本例中的button仅仅用了一次,仅仅在initView()方法中出现
     * 这里为了测试它的点击事件,所以重新find了这个button
     *
     * @return
     */
    publicButton getButton() {
        return(Button)findViewById(R.id.test_button);
    } 
}

4.2 测试activity的代码

测试activity需要继承ActivityInstrumentationTestCase2这个类,ActivityInstrumentationTestCase已经被废弃了,所以不用管它。这个类中提供了创建activity的方法,也提供了得到activity的方法,发送按键事件的方法,当然还有些别的方法。需要注意的是,类的构造函数必须是无参的,当传递按键前我们要屏蔽activity的touch事件,我个人建议不要去测试发送按键的事件,因为发送按键和当前输入法有很大关系,而且一般情况下我们完全没必要去测试用户输入不同数据的情况,直接用setText方法就好了。在测试任何view的方法前,我们都要让其获得焦点,然后给它一个按下的事件,这样我们就模拟了操作。

下面是测试类的代码,详细的解释都在注释里面了。

packagecom.kale.androidtest.test;
importandroid.app.Instrumentation;
importandroid.test.ActivityInstrumentationTestCase2;
importandroid.view.KeyEvent;
importcom.kale.androidtest.MyActivity;
public class MyActivityTest extends ActivityInstrumentationTestCase2<MyActivity>{
    privateInstrumentation mInstrumentation;
    privateMyActivity mActivity;
    publicMyActivityTest() {
        super(MyActivity.class);
    }
    @Override
    protected void setUp() throwsException {
        super.setUp();
        /**这个程序中需要输入用户信息和密码,也就是说需要发送key事件, 
         * 所以,必须在调用getActivity之前,调用下面的方法来关闭 
         * touch模式,否则key事件会被忽略 
         */  
        //关闭touch模式  
        setActivityInitialTouchMode(false);  
        mInstrumentation =getInstrumentation();
        //获取被测试的activity
        mActivity =getActivity();
    }
    /**
     * @description 该测试用例实现在测试其他用例之前,看edittext是否为空
     *
     */
    public voidtestPreConditions() {
        assertNotNull(mActivity.getEditText());
    }
    /**
     * @description 简单测试textview初始的字符串
     *
     */
    public voidtestGetText() {
        assertEquals("Hello world!", mActivity.getText());
    }
    /**
     * @description 测试button的点击事件,看看点击后textview的值有没有改变
     *
     */
    public voidtestClick() {
        //开新线程,并通过该线程在实现在UI线程上执行操作,这里是在主线程中的操作
       mInstrumentation.runOnMainSync(newRunnable() {
            @Override
            public voidrun() {
                //得到焦点
mActivity.getButton().requestFocus();
                //模拟点击事件
mActivity.getButton().performClick();
            }
        });
        assertEquals("kale", mActivity.getText());
    }
    /**
     * 该方法实现在登录界面上输入相关的登录信息。由于UI组件的 
     * 相关处理(如此处的请求聚焦)需要在UI线程上实现, 
     * 所以需调用Activity的runOnUiThread方法实现。 
     */  
    public voidtestInput()  
    {  
        //在UI线程中进行操作,让editText获取焦点
       mActivity.runOnUiThread(newRunnable()   
        {  
            @Override  
            public voidrun()   
            {  
                mActivity.getEditText().requestFocus();  
                mActivity.getEditText().performClick();  
            }  
        });  
        /*
         * 由于测试用例在单独的线程上执行,所以此处需要同步application, 
         * 调用waitForIdleSync等待测试线程和UI线程同步,才能进行输入操作。 
         * waitForIdleSync和sendKeys不允许在UI线程里运行 
         */
        mInstrumentation.waitForIdleSync();  
        //调用sendKeys方法,输入字符传。这里输入的是TEST123
sendKeys(KeyEvent.KEYCODE_SHIFT_LEFT,KeyEvent.KEYCODE_T, KeyEvent.KEYCODE_E,  
                KeyEvent.KEYCODE_S, KeyEvent.KEYCODE_S,  
                KeyEvent.KEYCODE_T, KeyEvent.KEYCODE_1,  
                KeyEvent.KEYCODE_2, KeyEvent.KEYCODE_3);  
       assertEquals("test123", mActivity.getEditText().toString());
    }  
}

4.3ActivityUnitTestCase

ActivityUnitTestCase也是activity的单元测试类,而且在理论上说它才是真正的activity单元测试。运行它的测试类后不会产生一个activity的界面,它会用底层来做处理,正因为如此,它里面不能有数据存储和交互依赖关系。个人了解后发现用它仅仅能测试下按键事件,或者是得到启动当前activity的intent、code等,还可以得到activity传递的code。调用下面的方法时会抛出异常信息,不应该去使用。

createPendingResult(int, Intent, int)  
startActivityIfNeeded(Intent, int)  
startActivityFromChild(Activity, Intent, int)  
startNextMatchingActivity(Intent)  
getCallingActivity()  
getCallingPackage()  
createPendingResult(int, Intent, int)  
getTaskId()  
isTaskRoot()  
moveTaskToBack(boolean)  

下面的方法可以调用,但一般不起任何作用,你可以使用getStartedActivityIntent()和getStartedActivityRequest() 来检查参数值。

startActivity(Intent)
startActivityForResult(Intent, int)

下面的方法也可以调用,一般也无效果,可以使用isFinishCalled() 和getFinishedActivityRequest检查传入的参数。

finish()
finishFromChild(Activity)
finishActivity(int)

我个人认为当你测试activity的intent或者传递的code可以用这个类,否则直接用ActivityInstrumentationTestCase2就好了,如果想要继续了解ActivityUnitTestCase,请参考:

http://blog.csdn.net/mapdigit/article/details/7589430

http://myeyeofjava.iteye.com/blog/1972435

五、测试Service

本段文字参考自:http://blog.csdn.net/yan8024/article/details/6271715

由于Service是在后台运行的,所以测试Service不能用instrumentation框架,继承ServiceTestCase的测试类可以对service进行针对性测试。ServiceTestcase不会初始化测试环境直到你调用ServiceTestCase.startService()或者ServiceTestCase.bindService. 这样的话,你就可以在Service启动之前可以设置测试环境,创建你需要模拟的对象等等。比如你可以配置service的context和application对象。

setApplication()方法和setContext(Context)方法允许你在Service启动之前设置模拟的Context 和模拟的Application.关于这些模拟的对象。

需要注意的是ServiceTestCase .bindService() 方法和Service.bindService()方法的参数不同的。ServiceTestCase.bindService() 方法只提供了以个intent对象。返回值方面ServiceTestCase.bindService()方法返回的是一个IBinder对象的子类, 而Service.bindService ()返回的是布尔值。

ServiceTestCase 默认的执行testAndroidTestCaseSetupProperly()方法。用于验证该测试类是否在跑其他测试用例之前成功地设置了上下文。

例子:

待测service

public class MyService extendsService{
    @Override
    publicIBinder onBind(Intent intent) {
        //TODO 自动生成的方法存根
        return null;
    }
    public int sum(int a, intb) {
        return a +b;
    }
}

测试代码:

packagecom.kale.androidtest.test;
importandroid.app.Service;
importandroid.content.Intent;
importandroid.os.IBinder;
importandroid.test.ServiceTestCase;
importandroid.test.suitebuilder.annotation.MediumTest;
importcom.kale.androidtest.MyService;
/**
 * @author:Jack Tony
 * @description  :
 * 
 * ServiceTestCase 默认的执行testAndroidTestCaseSetupProperly()方法。用于验证该测试类是否在跑其他测试用例之前成功地设置了上下文。
 * 
 * @date  :2015年2月18日
 */
public class MyServiceTest extends ServiceTestCase<MyService>{
    privateMyService mService;
    publicMyServiceTest() {
        super(MyService.class);
    }
    @Override
    protected void setUp() throwsException {
        super.setUp();
        getSystemContext();//A normal system context.
        //Sets the application that is used during the test. If you do not call this method, a new MockApplication object is used.
setApplication(getApplication());
        startService(new Intent(getContext(), MyService.class));
        //启动后才能得到一个service对象,如果测试时出现空指针异常,很可能是这里没有进行初始化。以防万一你可以在测试方法第一句用getService得到service对象
        mService =getService();
    }    
    @Override
    protected voidsetupService() {
        super.setupService();
    }
    @Override
    protected voidshutdownService() {
        //TODO 自动生成的方法存根
        super.shutdownService();
    }
    @Override
    protected void tearDown() throwsException {
        //TODO 自动生成的方法存根
        super.tearDown();
    }
    public voidtestPreConditions() {
        assertNotNull(mService);
    }
    public voidtestSum() {
        //mService = getService();        
        int sum = mService.sum(1, 2);
        assertEquals(3, sum);
    }
}

ServiceTestCase 方法说明:
getApplication()   返回被测试的Service所用的Application.
getSystemContext()  返回在setUp()方法中被保存的真的系统Context.
setApplication (Applicaition application)   设置测试被测试Service 所用的Application.
setUp()  得到当前系统的上下文并存储它。若要重写该方法的话,第一句必须是
super.setUp()  该方法在每个测试方法被执行前都执行一遍。
setupService()  生成被测试的Service , 并向其中注入模拟的组件(Appliocation ,Context)。该方法会被StartService(Intent )或者bindService(Intent)自动调用。
shutdownService()  调用相应的方法停止或者解除Service,然后调用ondestory(),通常该方法会被teardown()方法调用。
startService(Intent intent)  启动被测试的Service.如果用这个方法启动一个服务,那么该服务在最后回自动被teardown()方法关掉。
tearDown()  关闭被测试的服务, 确认在执行下个用例前所有的资源被释放,所以的垃圾被回收。 这个方法在每个方法执行完后调用。重写该方法上的话, 必须将super.tearDown()作为最后一条语句。

六、测试异步操作

异步任务可能是在activity中开始的,也可能是在service中开始的,运行环境根据实际情况而定,所以继承的测试类也不同。还得具体问题,具体分析。

6.1 思路

在测试方法中要将线程先wait,然后执行完成后调用notify去操作。如果是执行异步的操作,在测试方法中要将线程先wait,然后执行完成后调用notify去操作,比如:

    private final Integer LOCK = 1;
    public void test() throwsException {
        //……异步操作的回掉方法
        synchronized(LOCK) {
            LOCK.notify();
        }
        try{
            synchronized(LOCK) {
                LOCK.wait();
            }
        } catch(InterruptedException e) {
            Assert.assertNotNull(e);
        }
    }

上面的代码我没理解是什么意思,来自文章:http://blog.csdn.net/henry121212/article/details/7837074

6.2 例子

这个例子中我测试asyncTask,测试的代码来自stackoverflow,在百度上没有搜到任何有用的信息。下面的代码中我测试了asyncTask执行的结果。要点是重写onPostExecute()方法,在该方法中进行结果的判断,在最后调用countDown()来释放等待锁。代码执行时在UI线程中开启异步任务,然后执行等待命令,在异步任务的最后进行判断结果并停止等待。

    public void testLoginAsync2() throwsThrowable {
        //create a signal to let us know when our task is done.
        final CountDownLatch signal = new CountDownLatch(1);
        /*
         * Just create an in line implementation of an asynctask. Note this
         * would normally not be done, and is just here for completeness. You
         * would just use the task you want to unit test in your project.
         */
        final MyAsyncTask task = newMyAsyncTask() {
            @Override
            protected voidonPostExecute(String result) {
                super.onPostExecute(result);
                assertEquals("kale", result);
                //notify the count down latch
signal.countDown();
            }
        };
        //Execute the async task on the UI thread!
        runTestOnUiThread(newRunnable() {
            @Override
            public voidrun() {
                //执行异步任务
task.execute();
            }
        });
        signal.await();
        //signal.await(30, TimeUnit.SECONDS);
    }

源码下载:http://download.csdn.net/detail/shark0017/8451777

参考自:

http://blog.csdn.net/yan8024/article/details/6271715

http://blog.csdn.net/stevenhu_223/article/details/8298858

http://blog.csdn.net/henry121212/article/details/7837074

http://myeyeofjava.iteye.com/blog/1972435

http://blog.csdn.net/mapdigit/article/details/7589430

免责声明:文章转载自《Android单元测试》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇element UI 之table表格表头过长使用点点...显示,并添加鼠标移入悬浮显示20190627_解决ADB的device offline问题的两种方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

7、Semantic-UI之图标与按钮组

7.1 图标按钮   Semantic-UI中可以定义一组图标样式,并且可以在按钮中使用图标。 示例:定义一个图标按钮 <button class="ui black button"> <i class="unlock green icon"></i> </button> 示例:定义一组图标按钮 &...

android 定时器的使用

1、android中通常是使用AlarmManager来定时启动一个单次或重复多次操作的。具体的说就是我们通过AlarmManager设定一个时间和注册一个intent到系统中,然后在该时间到来时,系统为我们发送一个广播,即执行我们设定的Intent(要执行的操作),通常我们使用 PendingIntent来实现“要执行的操作”,PendingIntent...

点击按钮变色,松开按钮恢复原来的颜色

安卓软件中有这样一种效果:假设一个按钮是绿色,当你点击时变成黄色,松开时又变回绿色。现在介绍怎么实现这种效果 第一种方法:资源文件写法 在主布局文件中定义一个按钮 然后在value文件夹下的color.xml文件中定义要用的颜色 定义完颜色后在背景文件drawable文件下新建一个布局用于添加动作,下图btn.xml btn.xml中的写法如下图,原...

安卓完全退出程序的六种方法

1. Dalvik VM的本地方法   //杀死进程android.os.Process.killProcess(android.os.Process.myPid())  //抛异常强制退出  System.exit(0);2.任务管理器方法  //通过activity管理器重启ActivityManager activitymanager= (Activ...

android简易双屏支持【转】

本文转载自:http://blog.csdn.net/sfrysh/article/details/7463339 抱歉,之前说xorg的exa更新的时候恐怕一直不会更新了,没有做xorg开发了。转向android了。最近断断续续做了一些杂七杂八的android事情,都是一些不太容易的事情。简单的写了以下,android双屏的简易支持。纲领性的一些东西吧。...

使用 dumi 打包 React 组件库并生成文档站点

对于前端团队来说,公共组件库是必须的,紧接着就是完善组件库的文档 社区里关于快速生成文档的工具有很多,如 StoryBook、Docz、Gatsby 在调研了几种文档工具之后,最终我选择了 umi 家族的另一个成员:dumi 因为它集成了 docz,以及打包工具father-build,同时支持创建自己的Markdown 组件 当然最重要的是,我的项目是基...