Activity及其生命周期

一、Activity初步认识:【创建、配置、启动Activity】
(一)、创建Activity:
  • 创建Activity:继承于Activity或其子类,重写onCreate()方法。

(二)、Activity的注册配置: 作为四大组件之一的Activity,必须要在AndroidManifest清单文件中进行注册。如果没有配置,而又在程序中启动了该Activity,将抛出异常(ActivityNotFoundException)。
注册配置的核心代码:

<application


android:allowBackup="true"


android:icon="@drawable/ic_launcher"


android:label="@string/app_name"


android:theme="@style/AppTheme">


<activity


android:name=".MainActivity"


android:label="@string/app_name">


<intent-filter>


<actionandroid:name="android.intent.action.MAIN" />


<categoryandroid:name="android.intent.category.LAUNCHER"/>


intent-filter>


activity>


<activity


android:name=".HeadpicActivity"


android:label="@string/title_activity_headpic" >


activity>


application>


【附加思考】:
  1. 当在AndroidManifest清单文件中,设置多个页面都是默认启动页,会报错吗?如果不 报错,到底是执行哪个页面呢?
  2. 当在AndroidManifest清单文件中,如果不设置默认启动页,会报错吗?
(三)、启动Activity:
  1. 在Android应用里各组件之间通信使用Intent。一个Activity通过Intent来表达自己的“意图”。
  2. 常用有两种方式:
    • Intent intent = new Intent(MainActivity.this , NextActivity.class);
    • Intent intent = new Intent();
      •  intent.setClass(MainActivity.this , NextActivity.class);
  3. 常用启动方式有两种:
  • startActivity();
  • startActivityForResult();


(四)、Activity之间交换数据
  • 第一种方式:
    • 甲页面利用intent对象的putExtra()方法传值,乙页面利用getStringExtra()、getIntExtra()等系列方法来一一接收值;
  • 第二种方式:【常用】
    • 甲页面利用bundle对象来保存所有需要传递的数值,通过intent的putExtras()方法传值,乙页面利用intent对象的getExtras()方法返回bundle对象,将所有接收的数据放在bundle对象中,利用bundle的get系列方法一一去除数据。
        【备注:】如果甲页面使用putExtras()方法传值,则乙页面使用getExtras()接收值。如果甲页面使用putExtra()方法传值,则乙页面要使用getBundleExtra()方法接收值。
  • Activity之间是否可以传递对象呢?【掌握Serializable的用法
    • Serializable的用法
    • Parcelable的用法

1、传递一般数据的核心代码:
(1)、MainActivity页面:

publicvoid clickButton(View view) {

switch (view.getId()) {

case R.id.button_main_tonext:

Intent intent = new Intent(MainActivity.this, NextActivity.class);

Bundle bundle = new Bundle();

bundle.putString("myname", "hehaitao");

bundle.putInt("age", 16);

intent.putExtras(bundle);

startActivity(intent);

break;
}
}

(2)、NextActivity页面:

@Override
protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_next);

// 接收第一个页面的传值

Intent intent = getIntent();

Bundle bundle = intent.getExtras();

String name = bundle.getString("myname");

int age = bundle.getInt("age");

this.setTitle(name + ":" + age);
}


2、传递对象数据的核心代码:
(1)、Person对象核心代码:

publicclassPersonimplements Serializable {
private String userName;
privateintage;
privateintsex;

private List infoList;

public List getInfoList() {

returninfoList;
}

publicvoid setInfoList(List infoList) {

this.infoList = infoList;

}

public String getUserName() {

returnuserName;
}

publicvoid setUserName(String userName) {
this.userName = userName;
}

publicint getAge() {
returnage;
}
publicvoid setAge(int age) {
this.age = age;
}

publicint getSex() {
returnsex;
}

publicvoid setSex(int
this.sex = sex;
}
}
(2)、MainActivity页面:

publicclass MainActivity extends Activity {

private Person person = null;

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

List list = new ArrayList();

list.add("one");

list.add("two");

list.add("three");

person = new Person();

person.setUserName("wangxiangjun");

person.setAge(40);

person.setSex(1);

person.setInfoList(list);

}




publicvoid clickButton(View view) {

switch (view.getId()) {

case R.id.button_main_submit:

Intent intent = new Intent(MainActivity.this,

ReceiverActivity.class);

Bundle bundle = new Bundle();

bundle.putSerializable("person", person);

intent.putExtras(bundle);

startActivity(intent);

break;

}
}




@Override

publicboolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.main, menu);

returntrue;

}

}

(3)、MainActivity页面:

publicclass ReceiverActivity extends Activity {

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_receiver);

Intent intent = getIntent();

Bundle bundle = intent.getExtras();

// 接收Serializable对象

Person data = (Person) bundle.getSerializable("person");

setTitle(data.getUserName() + ":" + data.getAge() + ":"

+ data.getInfoList());
}
@Override

publicboolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.receiver, menu);

returntrue;

}
}

二、Activity——调用另一个Activity并返回结果
(一)、概念: 甲页面调用乙页面,当用户在乙页面完成任务后,程序自动返回到甲页面,而甲页面必须能够获取到用户在完成乙页面后传递的数据结果。
(二)、做法: 与普通的页面交换数据不同的是,要使用startActivityForResult()方法来启动另一个Activity。
(三)、示例代码:
1、MainActivity页面:

publicclass MainActivity extends Activity {

private ImageView imageView_main_headpic;

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

imageView_main_headpic = (ImageView) findViewById(R.id.imageView_main_headpic);

}




@Override

publicboolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.main, menu);
returntrue;
}




publicvoid clickButton(View view) {

switch (view.getId()) {

case R.id.button_main_selectpic:
Intent intent = new Intent(MainActivity.this, HeadpicActivity.class);

startActivityForResult(intent, 0);
break;
}
}




@Override

protectedvoid onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (requestCode == 0 && resultCode == 1) {

Bundle bundle = data.getExtras();

int imgid = bundle.getInt("imgId");

imageView_main_headpic.setImageResource(imgid);

}

}

}

2、NextActivity页面:

publicclass HeadpicActivity extends Activity {

private GridView gridView_headpic_show;

// 定义数据源

privateint[] imgIds = newint[] { R.drawable.img01, R.drawable.img02,

R.drawable.img03, R.drawable.img04, R.drawable.img05,

R.drawable.img06, R.drawable.img07, R.drawable.img08,

R.drawable.img09 };




@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_headpic);

gridView_headpic_show = (GridView) findViewById(R.id.gridView_headpic_show);
List> list = new ArrayList>();

for (int i = 0; i < imgIds.length; i++) {

Map map = new HashMap();

map.put("headpic", imgIds[i]);

map.put("picname", "头像—" + i);

list.add(map);
}




SimpleAdapter adapter = new SimpleAdapter(this, list,

R.layout.item_gridview_headpic, new String[] { "picname",

"headpic" }, newint[] {

R.id.text_item_gridview_picname,

R.id.imageView_item_gridview_headpic });

gridView_headpic_show.setAdapter(adapter);




gridView_headpic_show.setOnItemClickListener(new OnItemClickListener() {




@Override

publicvoid onItemClick(AdapterView<?> parent, View view,

int position, long id) {

Intent intent = getIntent();

Bundle bundle = new Bundle();

bundle.putInt("imgId", imgIds[position]);

intent.putExtras(bundle);

setResult(1, intent);

finish();

}

});

}




@Override

publicboolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.headpic, menu);

returntrue;

}

}


三、Activity生命周期 (一)、课堂引入:人的生命周期是怎么样的?
  • 胎儿
  • 婴儿
  • 儿童、少年、青年、中年
  • 突发变故
  • 老年
  • 死亡
(二)、Activity生命周期: 1、Activity一生中有七种不同的状态。
  • onCreate()
  • onStart()
  • onResume()
  • onPause()
  • onStop()
  • onRestart()
  • onDestroy()
【备注:】 A、七个生命周期组合:
  • onCreate、onStart、onResume:启动应用程序
  • onPause、onStop:失去焦点
  • onRestart、onStart、onResume:重新获得焦点
  • onPause、onStop、onDestroy :退出应用程序
B、七个生命周期按阶段划分:
  • onCreate() --- onDestroy()            完整生命周期    The entire lifetime
  • onStart() --- onStop()                    可见生命周期     The visible lifetime:
  • onResume() --- onPause()            前沿生命周期(焦点生命周期)    The foreground lifetime:


2、定义生命周期的作用:
  • ①当用户接一个电话或切换到另一个程序不会崩溃
  • ②当用户后台运行程序时不会销毁有价值的系统资源
  • ③当用户离开再返回你的应用时不会丢失用户的进程
  • ④当手机屏幕进行横竖屏切换的时候不会崩溃或者丢掉用户的进程
3、生命周期的金字塔图



(三)、实例代码操作 模仿以下操作,观察输出日志,找寻生命周期方法依次回调的规律:
  1. 打开主界面,后退键退出
  2. 打开主界面,进入第二个页面
  3. 打开主界面,模拟电话进入及挂机,再次显示主界面
  4. 打开主界面,HOME键退出
  5. 打开主界面,HOME键退出,再次启动app
  6. 打开主界面,点击该界面中捆绑退出事件的按钮后退出
  7. 打开主界面,切换横屏竖屏。
  • 生命周期执行的顺序:
04-23 03:51:29.750: I/MainActivity(741): ==MainActivity onCreate执行了04-23 03:51:29.759: I/MainActivity(741): ==MainActivity onStart执行了04-23 03:51:29.759: I/MainActivity(741): ==MainActivity onResume执行了04-23 03:52:04.780: I/MainActivity(741): ==MainActivity onPause执行了04-23 03:52:04.791: I/MainActivity(741): ==MainActivity onStop执行了04-23 03:52:04.791: I/MainActivity(741): ==MainActivity onDestroy执行了04-23 03:52:05.200: I/MainActivity(741): ==MainActivity onCreate执行了04-23 03:52:05.209: I/MainActivity(741): ==MainActivity onStart执行了04-23 03:52:05.329: I/MainActivity(741): ==MainActivity onResume执行了



【思考:】 两个Activity页面,点第一个中的按钮,进入第二个页面,此时点HOME退出程序。随后再次启动app,依次会执行哪些生命周期的回调方法。如果再点击返回,继续会执行哪些生命周期的回调方法? 请自己将依次调用的方法写在下面,不要借助机器调试。
【横竖屏切换时的生命周期问题的解决】 (一)、android:configChanges属性 对android:configChanges属性,一般认为有以下几点: 1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次 2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次 3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法 但是,自从Android 3.2(API 13),在设置Activity的android:configChanges="orientation|keyboardHidden"后,还是一样 会重新调用各个生命周期的。因为screen size也开始跟着设备的横竖切换而改变。所以,在AndroidManifest.xml里设置的MiniSdkVersion和 TargetSdkVersion属性大于等于13的情况下,如果你想阻止程序在运行时重新加载Activity,除了设置"orientation", 你还必须设置"ScreenSize"。 解决方法: AndroidManifest.xml中设置android:configChanges="orientation|screenSize

(四)、Activty生命周期的应用场景
  • 游戏过程中电话进入
  • Android音乐播放器

1、模拟Android音乐播放器,练习Activity生命周期的示例代码 目的:练习Activity生命周期,要明白不是所有的代码都写在onCreate()方法中,而是需要根据需求写在生命周期的不同的回调方法中。】

publicclass MainActivity extends Activity {





privatestaticfinal String TAG = "MainActivity";





privatestaticinti = 0;





private Button button_main_play;





private Timer timer = null;





privatebooleanflag = false;// 设置flag标记位的目的是避免程序一开启就执行,而是等点击了按钮后才开始。












@Override





protectedvoid onCreate(Bundle savedInstanceState) {





super.onCreate(savedInstanceState);





setContentView(R.layout.activity_main);





button_main_play = (Button) findViewById(R.id.button_main_play);





button_main_play.setOnClickListener(new OnClickListener() {





@Override





publicvoid onClick(View v) {





// 点击按钮后执行播放





playMusic();





// 设置flag标记位的目的是避免程序一开启就执行。现在点击了按钮,允许程序在再次执行的时候自动执行。





flag = true;





}





});





}












@Override





protectedvoid onStart() {





super.onStart();





}












@Override





protectedvoid onResume() {





super.onResume();





// 默认flag为false,不允许自动执行,而是当点击了播放后才允许执行。





if (flag) {





playMusic();





}






}












@Override





protectedvoid onPause() {





super.onPause();





// 当有电话进入,会回调onPause()方法,这个时候要让播放器停止。





// 定时器timer对象的cancel()方法能取消定时器。





timer.cancel();





}












@Override





protectedvoid onStop() {





super.onStop();





}












@Override





protectedvoid onRestart() {





super.onRestart();





}












@Override





protectedvoid onDestroy() {





super.onDestroy();





// 如果希望程序退出后,下次运行从头开始播放,可以将进度初始化为0.





// 如果点HOME退出,程序没有完全退出,下次播放应该从上次的进度继续执行。所以不应该初始化。





// 所以将初始化写在onDestroy(),而不写在onStop()中。(因为点HOME退出不会回调onDestroy()方法。)





i = 0;





}












@Override





publicboolean onCreateOptionsMenu(Menu menu) {





getMenuInflater().inflate(R.menu.main, menu);





returntrue;





}












publicvoid playMusic() {





// 用定时器输出数字来模拟播放器播放的效果





timer = new Timer();





// 定时器timer对象的sechedule()方法有三个参数,第一个表示定时执行的任务,第二个参数表示延迟时间,第三个参数表示间隔的时间





timer.schedule(new TimerTask() {












@Override





publicvoid run() {





Log.i(TAG, "==i=" + i);





i++;





}





}, 0, 1000);





}





}





四、任务回退栈 (一)、任务Task: 1、概念: 一个任务(task)就是在执行某项工作时与用户进行交互的Activity的集合。这些Activity按照被打开的顺序依次被安排在一个堆栈中(回退栈)。

2、主屏页面: 设备的主屏是大多数任务的启动位置,当用户触摸一个应用程序启动器图标(或者app快捷图标),应用程序的任务就会在前台显示。如果相关应用程序的任务不存在,那么就会有一个新的任务被创建,并且应用程序打开的“主”Activity会作为任务中的根Activity。
(二)、回退栈: 1、概念: 当前的Activity启动了另一个Activity时,这个新的Activity被放到了堆栈的顶部,并且带有焦点前一个Activity并没有消失,而是保存在回退栈中,此时它处于停止状态 当用户按下回退按钮时,当前的Activity会被从回退栈的顶部弹出(这个Activity被销毁),而前一个Activity被恢复。堆栈中的Activity不会被重新排列。因此,回退栈的操作跟后进先出的对象结构是一样的。 在用户按下回退按钮时,当前Activity被销毁,并且前一个Activity被恢复。如果用户继续按回退按钮,那么回退栈中的每个Activity会被依次弹出,前一个Activity会被显示,直到用户返回主屏(或者返回到任务开始时运行的那个Activity)。当所有的Activity从回退栈中被删除时,这个任务就不再存在了。


图1:用一个时间表显示了当前回退堆栈中的Activity之间在每个时间点的处理过程

2、多个任务: 图2. 两个任务:任务B在前台接受用户交互,而任务A则在后台等待被恢复。
【注意:】后台中可以同时拥有多个任务,但是如果用户同时运行了很多后台任务,系统为了回收内存可能销毁一些后台的Activity,从而导致Activity的状态丢失。
        因为回退堆栈中的Activity不曾被重新排列,因此如果允许用户从多个Activity中启动一个特殊的Activity,那么就会创建一个新的Activity实例,并且在堆栈的顶部弹出(而不是把之前的Activity实例带到堆栈的顶端)。这样在你的应用程序中一个Activity就可能被实例化多次(甚至来自不同任务)。


(三)、Activity和Task的默认行为的总结:
1、当Activity A启动Activity B时,ActivityA被终止,但是系统保留了它的状态(如滚动条的位置和录入表单的文本)。如果用户在Activity B中按回退按钮,Activity A会使用被保存的状态来进行恢复。
2、当用户通过按主页(Home)按钮离开一个任务时,当前的Activity会被终止,并且被放入后台。系统会保留任务中每个Activity的状态。如果用户随后通过选择启动图标来恢复这个任务,那么任务会来到前台,并且恢复了堆栈顶部的Activity。
3、如果用户按下回退按钮,当前的Activity会从堆栈中被弹出并且被销毁。堆栈中的前一个Activity会被恢复。Activity被销毁时,系统不会保留Activity的状态。
4、Activity能够被实例化多次,甚至来自其他任务。

Activity启动模式         在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作。在Android中Activity的启动模式决定了Activity的启动运行方式。Android总Activity的启动模式分为四种: (一)、Activity启动模式设置:         android:launchMode="standard" />

(二)、Activity的四种启动模式:

    1. standard(备注:standard是系统默认的启动模式。)

        标准启动模式,每次激活Activity时都会创建Activity,并放入任务栈中。每个窗体的getTaskId()保持不变,但是this.hashCode()发生改变。

    2. singleTop

        如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,而不会创建新的Activity对象,不过它会调用onNewIntent()方法。如果栈顶部不存在就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。会回调onNewIntent()方法。

    3. singleTask

        如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。 

        和singleTop在名字上即可看出区别,即singleTop每次只检测当前栈顶的Activity是否是我们需要请求创建的,而singleTask则会检测栈中全部的Activity对象,从上向下,如果检测到是我们所请求的则会消灭此Activity对象上面的对象,直接把检测到的我们需要的Activity置为栈顶。

    4. singleInstance

        与singleTask模式的区别是存放singleInstance模式窗口对象的回退栈不能有其他任何窗口对象。因此如果该窗口不存在,则要新建任务来存放该singleInstance模式窗口。也就是说getTaskId()会发现任务id发生了变化。

        此启动模式和我们使用的浏览器工作原理类似,在多个程序中访问浏览器时,如果当前浏览器没有打开,则打开浏览器,否则会在当前打开的浏览器中访问。此模式会节省大量的系统资源,因为他能保证要请求的Activity对象在当前的栈中只存在一个。

总之,在开发Android项目时,巧妙设置Activity的启动模式会节省系统开销和提高程序运行效率

Activity的三种状态:

a)     运行状态

b)     暂停状态

c)     停止状态

运行状态:

     当Activity在屏幕的最前端,也就是当前显示页面时候,它是可见的并且有焦点,可以处理用户的操作:比如点击、双击、长按等,也就是激活运行状态,处理各个监听器的功能。

当内存不足的时候,Android会先封杀堆栈底层的Activity,也就是最先打开的Activity,类似于数组的堆栈压栈操作。

暂停状态:

   在Activity可见但没有焦点,并且用户对Activity的操作没有响应,这样的状态是暂停状态。我在使用手机的时候,比如我打开了一个Activity,但在我退出的时候会弹出一个提示是否退出的对话框,这时候,我们之前打开的应用就变成了半透明效果并且处于暂停状态也没有焦点,我们做任何操作都无效;当前的焦点在提示退出的对话框上,所以这个对话框就处于运行状态,也就是激活状态中,我们可以做任何操作。

停止状态:

当Activity完全不可见的时候就处于停止状态。比如手机多任务状态运行的时候,很多程序都不在屏幕上显示,我们在不同的程序中切换不同的Activity,很多程序就在不停地做运行状态—>暂停状态—>停止状态的切换。这个过程就是Android程序的生命周期中要做的事情。

生命周期事件:

Activity状态的变化是随着我们的操作进入的,状态的改变会触发一些事件,也就是生命周期事件。一共有七个生命周期事件:

Void onCreate(Bundle savedInstanceState)

protected void onCreate(Bundle savedInstanceState)一个 Activity 的实例被启动时调用的第一个方法。一般情况下,我们都覆盖该方法作为应用程序的一个入口点,在这里做一些初始化数据、设置用户界面等工作。大多数情况下,我们都要在这里从 xml 中加载设计好的用户界面。

Void onStart()

该方法在 onCreate() 方法之后被调用,或者在 Activity 从 Stop 状态转换为 Active 状态时被调用。

Void onRestart()

Void onResume()

在 Activity 从 Pause 状态转换到 Active 状态时被调用。

Void onPause()

Void onStop()

在 Activity 从 Active 状态转换到 Stop 状态时被调用。一般我们在这里保存 Activity 的状态信息。

Void onDestroy()

在 Active 被结束时调用,它是被结束时调用的最后一个方法,在这里一般做些释放资源,清理内存等工作。

总结:

一、    Activity从创建到进入运行状态所触发的事件:

onCreate() —>onStart()—>onResume()

二、    当Activity从运行状态到停止状态所触发的事件:

onPause()—>onStop()

三、    当Activity从停止状态到运行状态所触发的事件:

onRestart()—>onStart()—>onResume()

四、    当Activity从运行状态到暂停状态所i触发的事件:

onPause()

五、    当Activity从暂停状态到运行状态所触发的事件:

onResume()

具体关系如图所示

解释如下:

正在运行的Activity 处在在栈的最顶端,它是运行状态的;当有新Activity进入屏幕最上端时,原来的Activity就会被压入第二层,如果他的屏幕没有被完全遮盖,那么他处于Pause状态,如果他被遮盖那么他处于Stop状态。当然不管你出于任何一层,都可能在系统觉得资源不足时被强行关闭,当然关闭时在栈底的程序最先被关闭。 

譬如:当你在程序中调用 Activity.finish()方法时,结果和用户按下 BACK 键一样:他告诉 Activity Manager该Activity实例可以被“回收”。随后 Activity Manager 激活处于栈第二层的 Activity 并重新入栈,把原 Activity 压入到栈的第二层,从 Running 状态转到 Paused 状态。 

当你调用 Activity.finish()方法时,结果和用户按下 BACK 键一样:告诉 Activity Manager 该 Activity 实例完成了相应的工作,可以被“回收”。随后 Activity Manager 激活处于栈第二层的 Activity 并重新入栈,同时原 Activity 被压入到栈的第二层,从 Active 状态转到 Paused 状态。例如:从 Activity1 中启动了 Activity2,则当前处于栈顶端的是 Activity2,第二层是 Activity1,当我们调用 Activity2.finish()方法时,Activity Manager 重新激活 Activity1 并入栈,Activity2 从 Active 状态转换 Stoped 状态,Activity1. onActivityResult(int requestCode, intresultCode, Intent data)方法被执行,Activity2 返回的数据通过 data参数返回给 Activity1。







更多相关文章

  1. android activity启动过程分析
  2. Android(安卓)GridView 滑动条设置一直显示状态(推荐)
  3. Android(安卓)五大存储方式详解
  4. Android学习11-----多媒体技术(5) 媒体录制
  5. Android中的Intent Filter匹配规则介绍
  6. Android初始ViewRoot和DecorView
  7. 在launcher 2.1上实现2.2的屏幕标记
  8. 2019年Android中高级工程师部分面试题
  9. android.support.v7.widget.TintContextWrapper cannot be cast

随机推荐

  1. Android中Cursor关闭的问题
  2. Android应用程序资源管理器(Asset Manager
  3. Android:增强目录选择器对话框
  4. Android(安卓)- 支持不同的设备
  5. Android(安卓)Notification 详解,使用Medi
  6. 如何检索Android设备的唯一ID
  7. (Android实战系统二)Android网络互动传输
  8. 开发者大会传递信号:Android开发者将越来
  9. 安卓Android开发视频教程大全50GB/安卓基
  10. (转)Android内存管理机制之一:lowmemory k