- 启动虚拟机时,在 launch options 窗口中 有个 wipe user data ,勾选它,将会让虚拟机 【恢复出厂设置】
2.【如果想让自己的应用程序有多个启动图标:】
为一个应用的 多个Activity都设置该过滤器,使之都成为优先启动的Activity,并且为这几个Activity设置icon,与 label属性
那么部署后将发现手机中会有多个图标(icon与label都不同),但是实际上只有一个应用程序。
该过滤器写法:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
【如果想让自己的应用程序没有 任何页面且没有启动图标(隐秘):】
将清单文件的所有Action都去掉这个过滤器:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
注意:在安装4.0之后,如果安装的程序没有任何页面,则他所设置的广播接收器就不会生效。---安全性提高了
-
--------隐式意图---------
[打开电话拨号器 ]
/* -------简写------- Uri uri = Uri.parse("tel:119"); Intent intent = new Intent(Intent.ACTION_DIAL_DIAL,uri); startActivity(intent); */ /* -------详细--------- Intent intent = new Intent(); intent.setAction(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:119")); startActivity(intent);*/
4.--------显示意图---------
[Activity跳转--启动一个Activity]
Intent intent = new integerent(); //new Intent(MainActivity.this, SecondActivity.class); 这样写则无需 setClass()
intent.setClass(MainActivity.this, SecondActivity.class);
startActivity(intent);
- string.getBytes(String charsetName) ; //使用指定的字符集(编码方式),将字符串编码成一个 字节数组,并返回
6.-----------------------------------【Activity两种启动方式,四种启动模式】-------------------------------------------
【Activity的两种启动方式】:
普通方式:startActivity(intent);
另一种方式:startActivityForResult(intent,requestCode); //【如果需要获得 目标Activity关闭时的 回传数据,则用这种方式】
//此处的 for 可以翻译为:为了,即:开启一个Activity为了得到结果
【 Activity的四种启动模式】:
1.清单文件-->Activity节点有:android:launchMode属性.用于标识Activity的启动模式
2.有四个取值分别为: standard : 标准模式--【默认】,如果此Activity重复打开多次,则就会重复进栈
singleTop : 单顶模式 ----开启此Activity前会检查 栈顶,如果二者相同则复用栈顶,而不是重新压栈
(在栈顶之下可以重复存在)
singleTask : 单任务模式---开启Activity时,会检查任务栈中是否有相同的Activity,若有则复用。
且被复用的Activity上方的其他Activity都会被销毁,但下方的不影响。
(此Activity在整个栈中都只有一份)
singleInstance :单任务栈模式--开启此Activity时,会单独创建一个任务栈--且独享,再开则复用 (如果在其他模式的Activity上打开此Activity则会携带整个任务栈位于前部)
--例如:来电界面
7.一个正常运行的Activity,突然切换为横屏或竖屏:【会先销毁再创建】 onPause–>onStop–>onDestroy–>onCreate–>onStart–>onResume
【因此Activity的横竖屏方向 最好是在清单文件中设置好 】
【 或者设置Activity属性 android:configChanges="orientation|keyboardHidden|screenSize"】
8.在xml布局文件中使用 include标记可以在本布局文件的指定位置处,引用其他的布局文件:
例:
<include
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="@layout/activity_find"
/>
-------------------------【单击某个按钮弹出几种形式的菜单】–OptionMenu,ContextMenu,PopupMenu ---------------------------------
9.安卓中实现单击某个按钮,弹出optionMenu(选项菜单) .只需要调用Activity.this.openOptionsMenu();方法就可以了
例:myButton.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v){
MainActivity.this.openOptionsMenu(); //单击按钮弹出 OptionMenu
}
});
10.单击某个按钮, 弹出(ContextMenu)上下文菜单:
//前提是:首先创建了 ContextMenu对象 ,然后做参数传入此方法
this.openContextMenu(view)
14.Spinner 的两种显示模式: (对话框,下拉列表)
设置方式:
android:spinnerMode : 用来改变Spinner控件的显示样式,
两个属性值 :[比如:设置为弹出列表(dialog),下拉列表(dropdown)]
-
安卓开发中对于需要访问数据库的项目一般建议创建:
1.MySQLiteOpenHelper 类 ------用于创建数据库,与初始化表结构,更新表结构 2.MyStudentDBDao 类 ------数据库操作类,用于做增删改查 3.MyBaseAdapter 类 -------用于做数据展示时的数据适配器
16.AdapterView(如:ListView)的数据刷新-----当数据源的内容发生改变后,就应该对Adapter进行数据刷新
前提是:传给ListView(AdapterView)的list指向不能被改变,需要从始至终指向同一个内存,
一般调用:this.adapter.notifyDataSetChanged();
并且建议在 onStart 方法中调用 数据刷新方法
17.【常见的Dialog有十种】:普通Dialog,多按钮普通Dialog,普通列表Dialog,单选列表Dialog,多选列表Dialog,,自定义Dialog,
环形进度条Dialog,水平进度条Dialog ,以及:DatePickerDialog和TimePickerDialog
【详见】:...\笔记\android 开发\安卓开发—2\Dialog--对话框 文件夹 】
快速创建一个Dialog:因为此处可以使用链式方式编写代码 :
new AlertDialog.Builder(MainActivity.this)
.setMessage("哈哈哈哈")
.setIcon(R.drawable.ic_launcher)
.setTitle("我是普通对话框")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel(); //取消对话框
}
})
.create().show();
-
【从MainActivity跳转到目标Activity然后返回MainActivity 】
【建议使用】: 销毁目标Activity的方式,让目标Activity出栈,由于MinaActivity没有被销毁毁,则会自动返回MainActivity 【不建议直接】:从目标Activity用 显示意图(setClass(...))的方式,调回源Activity
19.目前发现:安卓中常见的可以使用链式调用的方式编写代码的有:
AlertDialog 与 SharedPreferences ,Notification
例:new AlertDialog.Builder(MainActivity.this)
.setMessage("哈哈哈哈")
.setIcon(R.drawable.ic_launcher)
.setTitle("我是普通对话框")
例:this.sp.edit().putString("enableLogin_str", "true").commit();
例://使用链式调用创建通知对象----3.0以上高版本的写法
Notification notif = new Notification.Builder(this)
.setContentTitle("我是大标题")
.setContentText("我是通知内容")
.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher))
//.setContentIntent(pendingIntent) //[设置延期意图,可以实现单击通知栏打开其他的系统组件 ]
.build();
【注意】:创建Notification对象的链式调用发送,只有在 Android3.0(API 11)以上的机器上才能使用。
如果想让自己的Notification兼容低版本手机:则可以这样写:
//兼容低版本的写法 用过时的方法
Notification noti = new Notification(R.drawable.ic_launcher, "接收到了一条通知", System.currentTimeMillis());
//[发送通知
nm.notify(2, noti);
- 【获取当前程序的版本号】
public static String getAppVersion(Context context) {
String version = “0”;
try {
version = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return version;
}
——————————————————————————————————————
21. new Date().toLocaleString() //虽然已经被废弃,但是效果依然不错
效果如:2016年 10月 12日 01:51:44
——————————————————————————————————————————
22.【动态设置颜色的技巧】:
Color.parseColor("#ff4081")); //将16进制的颜色值解析成int 型的 Color值
例:button1.setBackgroundColor(Color.parseColor("#ff0000")); //将此Button 的颜色设置为 红色
————————————————————————————————————————————————————————————————
23,对于SQLiteDataBase数据库的 表都建议使用 id 字段做主键 (自增)且 Integer 类型(实际上是:32位的int类型)
【账号id用于修改,删除账号时做标识使用,数据展示时则根据账号在容器中的位置来决定】
db.execSQL("create table account_Table(accID integer primary key autoincrement,accTitle varchar(50)");
获取主键的值:cursor.getInt();
accBean.setAccID(cursor.getInt((cursor.getColumnIndex("accID")))); //填充id 字段
id 做标识来删除记录:
db.execSQL("delete from account_Table where accID=? and accTitle=? ",new Object[]{accBean.getAccID(),accBean.getAccTitle()});
——————————————————————————————————————————————————————————————————————————————————
24.
1.获取ROM 的根路径:通过 Environment可以获取ROM的根路径 ---------//即:/data
Environment.getDataDirectory().getPath();
2.获取应用程序的私有目录(包含在ROM中):
有两种方式:1.context.getFileDir().getPath(); //获取私有目录的路径(data/data/packagename/files)
2.context.openFileIn(Out)put(name,mode) //获取私有目录的输入输出流
2.1:获取data/data/packagename/Cache目录的路径
context.getCacheDir().getPath();
3.获取SDCard的路径:通过 Environment可以获取sdcard的路径
Environment.getExternalStorageDirectory().getPath(); ------ :/storage/sdcard1 ------真正的SD卡的路径
注意:操作SD卡必须注册权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————
25.关于 JavaBean 与 Json 数据的转换建议使用 谷歌提供的 Gson 框架
1.首先在项目中导入 gsonxx.jar 包。
【注意】:gson包导入成功后,编译项目时 bin\dexedLibs\目录下自动会将 gson.jar 包添加进来
因此导入成功后无需考虑程序在 用户手机上运行时 是否支持 gson 包
2.然后使用可以用:toJson()系列的方法 将 java对象转换成 json 数据
fromJson()系列的方法用于将JSON数据转换为相应的Java对象
—————————————————————————————————————————————
-
分享功能实现 有两种方式:1.【使用系统自带的分享接口: (会显示一个分享列表供用户选择)】
例: //【分享文字】 Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_TEXT, "This is my Share text."); shareIntent.setType("text/plain"); //设置分享列表的标题,并且每次都显示分享列表 startActivity(Intent.createChooser(shareIntent, "分享到")); 2.【使用第三方的 分享功能 sdk 】
——————————————————————————————————————————————————————————————————————————————————————————
29.使用四大组件 都需要在清单文件中进行注册,但广播接收器例外;因为它还可以动态注册(且ResultReceiver也无需注册)。
且四大组件都可以定义IntentFilter。
且四大组件的创建都是:创建一个类然后继承自某个组件类(例:MainActivity extends Activity)
MyFristService extends Service
MyReceiver extends BroadcastReceiver
AccountProvider extends ContentProvider
——————————————————————————————————————————————————————————————————————————————————————————
30。屏蔽Back键:
由于按下Back键后系统会调用:onBackPressed();方法,而该方法默认会调用父类的onBackPressed(),且父类的该方法内部就是 finish();
因此将对父类该同名方法的调用代码 注释掉时候就可以实现back键的屏蔽了
例:
@Override
public void onBackPressed() {
// super.onBackPressed();
}
-
设置当前线程睡眠可以用,Thread.sleep(...) ,或者Thread.currentThread().sleep(time) ,但是都会需要异常处理
安卓中可以使用 SystemClock.sleep(ms) 来实现睡眠,且不需要做异常处理、
二者区别:Thread.sleep()是java提供的函数。在调用该函数的过程中可能会发生InterruptedException异常。
SystemClock.sleep()是android提供的函数。在调用该函数的过程中不会发生InterruptedException异常,中断事件将要被延迟直到下一个中断事件。U
————————————————————————————————————————————————————————————
32.对于接口两种处理方式:
1.创建一个类实现该接口
2.查看并使用接口的子类
接口可以隐藏代码的细节,让程序员暴露自己想暴露的部分代码
-
关于AIDL与IPC的一些面试题:
AIDL(Android接口定义语言) 可以用于实现 IPC(跨进程通信)
——————————————————————————————————————————————————————————————————————
34.【安卓中实现跨进程通信有多种方式:
其中有4种方式正好对应于android系统中4种应用程序组件[Activity、Service、Broadcast 和ContentProvider--ContentResolver]】:
1.其中Activity可以跨进程调用其他应用程序的Activity --------------------------【使用隐式意图】
2.Service和Content Provider类似,也可以访问其他应用程序中的数据,(但ContentProvider返回的是Cursor对象,而Service返回的是Java对象)
--------------------------【AIDL】
3.Broadcast可以向android系统中所有应用程序发送广播(有序广播可以携带数据),而需要跨进程通讯的应用程序可以监听这些广播;
----------------------------【BroadcastReceiver】
4.ContentResolver可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),当然,也可以对其他应用程序的数据进行增、删、改操作;
--------------------------【Cursor】
——————————————————————————————————————————————————————————————
35. 获取到Cursor对象后必须先进判断,满足条件才能使用cursor:
if(cursor!=null &&!cursor.isClosed() && cursor.getCount()>0){ //游标对象不为空,且结果集没有关闭,且查询到的数据不为空
....
//使用完记得资源清理
cursor.close();
db.close();
}
-
如何将一个Android工程 变成一个 类库文件?
在项目上 右键-->Properties-->Android--》勾选 is Library 就可以吧自己的项目标志成一个 类库。---但标志后就不可以部署运行了 同理 取消勾选 is Library 就可以将一个 类库文件变回原来的 安卓项目文件----就可以部署运行了
37.【注意:接收一个新项目时,首先打开eclipse–》window–>Preferences–》workspace—>建议将编码改成UTF-8】
————————————————————————————————————————————————————
38.versionName和versionCode的区别和用处:
versionCode :版本号 ,用于与服务端的版本号进行比较,看是否需要更新应用。
versionName : 版本名称,用于提示给用户,如 :1.0.0 ,最后一位代表修复原有版本的bug
倒数第二位代表更新了部分功能
第一位代表项目重大更新,例:代码重构,界面变化,大部分功能添加
————————————————————————————————————————————————————————
39.【minSdkVersion、maxSdkVersion、targetSdkVersion, Compile With 四个数值到底有什么区别?】
> minSdkVersion, maxSdkVersion 是项目支持的最低sdk版本和最高sdk版本. 在安装apk前,系统会对这个两值进行判断, 决定当前系统是否可以安装。 且一般maxSdkVersion不会设置
>targetSdkVersion:会告诉系统,此版本已经经过充分测试,那么程序运行在该版本的系统时,就不会做过多额外的兼容性判断.运行效率会高一些。
> Compile With 是项目编译时的sdk版本:一般都选择较高的编译版本
【补充:在清单文件中会标明 最低以及目标版本,然后编译版本则写在 project.properties文件中】
————————————
40.Eclipse中:选择方法名或者类名处 使用快捷键:alt+shift+J 即可实现快速文档注释。
Eclipse中:在实体类中:alt+shift+s 弹出窗口后,按下s 即可进入 geter/seter方法设置窗口。
Eclipse中:如果需要自动生成toString()方法:右键–》source–》generate toString。
————————————————————————————————
41. 【学习过程中 版本检测,app下载更新等功能的实现:】
本程序为了简便则直接在本机的 Tomcat根目录/webapps/ROOT/目录下放置文件然后直接访问即可。
例:首先将Json字符串保存成一个文本文件(mobileSafe_Update02.json),然后存储到Tomcat根目录/webapps/ROOT/目录下
开启TomcatServer后:用浏览器直接访问 http://localhost:8080/mobileSafe_Update02.json 即可看到json文本。
例2:同理直接将mobilesafe1.0.1.apk放置到 Tomcat根目录/webapps/ROOT/目录下。
开启TomcatServer后:用浏览器直接访问 http://localhost:8080/mobilesafe1.0.1.apk 即可弹窗提示下载apk文件。
【但是实际开发中,用手机访问网络因此不能使用电脑的localhost。】
解决方式:
1.购买服务器,注册域名然后获得一个公网的ip,再用手机访问
2.使用开启了Tomcat服务的电脑的IP地址(内网ip)。---前提是手机与电脑在同一个局域网下
3.或者在自己的电脑上使用工具将ip映射到公网上。---例如:花生壳等工具即可实现。
4.【Google提供了解决方案:直接在模拟器使用10.0.2.2就可以访问到电脑上的Tomcat服务器 】---【推荐使用】
例:开启Tomcat后,在模拟器的浏览器上输入:http://10.0.0.2:8080/mobilesafe1.0.1.apk 即可提示下载apk
42.在安卓开发中应该尽量使用Log.xxx打印日志调试程序。而少用System.out.pritnln();
eclipse中:ctrl + shift + x :将选中的字母转换成大写字母 ,ctrl+shift+y :变小写。
43.小技巧:也可以利用Handler–Message机制来实现提示用户程序所出现的异常情况;
try{
…
}catch (MalformedURLException e) {
e.printStackTrace();
//小技巧:也可以利用Handler–Message机制来实现提示用户程序所出现的异常情况
msg.what = URL_ERROR;
} catch (IOException e) {
e.printStackTrace();
msg.what = IO_ERROR;
}
finally{
handler.sendMessage(msg);
}
小技巧:可以自行封装一些Utils类 例如:ToastUtils.java
- 小技巧:选中自定义的TextView类名然后右键–》copy Qualified name -->即可获得该类的全类名。com.xx.xxx
此方法可以适用于任何类的类名上,获取类的全名。
45.有时重写了某个方法发现方法的参数 使用 arg0,arg1…这样表示,则说明这个类没有关联源代码。
解决方案:添加源码关联即可。
46.handler.sendEmptyMessageDelayed(ENTER_HOME, 4000); //发送一个消息,让他延迟4秒后再做处理。
47.可以专门创建一个类(MyConstantValues)用于保存和管理项目中需要的常量.使用时:MyConstantValues.XXX 即可。
48.实际开发中可以 按照组件分包。例如:com.hzy.xxx.activity ,com.hzy.xxx.service …
49.布局文件中,在父控件标签后可以用 android:padding=“10dp” 设置内边距为10dp。
,也可以在子控件中设置 android:layout_margin=“10dp” 设置内边距为10dp。
50.访问项目中 assets 资源目录下的文件。
例://[1]:首先获取assets资产目录管理器
AssetManager assetManager = getAssets();
//[2]:然后获取assets 资产目录下指定文件的输入流
InputStream inputStream=null;
try {
inputStream = assetManager.open(dbName);
} catch (Exception e1) { e1.printStackTrace();
}
——————————————————————————————————————————————————————————————————————————
51.【从整个Eclipse中的的某个项目中搜索关键字。】----反编译常用
选中整个项目--》ctrl + h ,即可全项目搜索某一个字符串了。
【查看一个类的继承结构】
选中一个类 :ctrl+T 即可查看
52.【利用震动器实现手机震动效果】
//获取震动器对象
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
//开始震动。需要注册震动权限<uses-permission android:name="android.permissionsion.VIBRATE"/>
vibrator.vibrate(1000);
//规律震动,(暂停时间,震动时间,暂停时间,震动时间) ,重复次数
//vibrator.vibrate(new long[]{2000,1000,2000,1000}, 2);
//取消震动
vibrator.cancel();
52.在Service中虽然也可以弹出Toast但是必须使用getApplicationContext();切记不能使用this。
Toast.makeText(getApplicationContext(), "来电显示服务已经关闭!", 0).show();
-
[透明Activity的实现.只需要在清单文件中为这个Activity标签设置 theme属性值即可:]
例:Activity背景全透明: <activity android:name=".activity.SetToastLocationActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar" >
[如果需要半透明效果则可以在 此Activity的布局文件中设置 底层布局的 background属性为一个半透明的色值(例:#acfc)即可.]
54.改变一个控件的坐标有两种方式:
例:1.view.setX() , view.setY(); //左上角点坐标
2.view.layout(int l, int t, int r, int b) //左,上,右,下。四个顶点的坐标。
55.【可以用两个连续的单击事件作为双击事件。实现控件的双击事件监听。一般设置时间间隔为500毫秒之内。】
query_number_address_Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(System.currentTimeMillis()-firstClickTime<500){
//双击实现 toast_imgview居中
toast_imgview.setX(screen_width/2-toast_imgview.getWidth()/2);
toast_imgview.setY(screen_height/2-toast_imgview.getHeight()/2);
}else{
//单击,则记录第一次点击的时间
firstClickTime=System.currentTimeMillis();
}
}
};
-
★【如果使用了自增长的id做主键,则必须重新开启子线程获取数据,刷新适配器。】
并且由于数据库中记录的id,不会自动刷新,例如:id为11的记录被删除了,则id为12的记录id仍然为12。因此11这个id就没有记录了。 且在beans集合中对象是从0开始排列的,而数据库中 自增的id字段则是从1开始排列的。 】
【在数据库中delete或update数据记录时 :
强烈建议使用 id字段与其他字段结合做删除条件。否则如果只用 phonenumber做删除条件。
因为一旦数据库中有相同的phonenumber,则在删除数据时会出现 bug .
】
- 【添加一个本地刷新方法,每当完成数据库增删改后 就将增删改同步到本地的 beans 中。然后开启本地数据刷新。而不是请求下一页。】
58.- 清单文件中可以指定本应用程序安装位置
manifest根标签具有这样的属性,用来指定apk的安装位置, 缺省值是手机内存 android:installLocation="auto", 可以修改为auto, 表示优先使用手机内存, 如果内存不够,再使用sdcard. 不建议强制安装在sdcard,因为某些手机没有sdcard,会导致安装失败.设置完成后,就可以在系统应用管理中,移动apk的安装位置了.
59.【让ImageButton实现像是ImageView一样单纯的展示图片,而没有背景(即:透明背景)。】
【只需将 ImageButton的background属性设置为 android:background="@null" 然后用 android:src属性设置需要展示的图片即可。】
60.由于ViewPager属于 android.support.v4.view.ViewPager ,因此如果想看到源码则必须按照如下步骤:
[1]:找到项目中libs下 android-support-v4.jar --右键--》Add To Build Path
[2]:然后在 Referenced Libraries中 找到 android-support-v4.jar 中的 android.support.v4.view.ViewPager类。
[3]:此时就可以点开 ViewPager.class ,然后可以 Attach Source ,选择 /sdk/extras/android/support/v4/src 即可看到源码。
61.由于TextView默认是没有点击事件的,因此如果想为TextView设置点击事件则有两种方式:
1.在java代码中为TextView设置单击事件监听
2.在布局中为TextView设置 onClick属性值为一个方法名。----前提是需要先设置 onClickable="true" 才行。
62.当多个控件有共同的一些属性值时:
可以首先编写好一个控件的布局代码,然后在该标签中 ctrl+1 选择 Extract style ,就可以快速的抽取成 style标签。
使用这个小技巧,可以避免手动复制粘贴 布局代码到 style.xml文件中。
63.解决模拟器不能输入中文的问题(无论是用软键盘,还是物理键盘都不行):
解决方案:进入模拟器 Setting --》Language&Input -- 》Language --》选择简体中文 ---》键盘选择 谷歌拼音
--》然后在任意EditText中点击--》选择键盘 谷歌拼音,此时就可以输入中文了。
64:【实现侧边栏(侧滑面板)效果有四种方式】:
△创建一个自定义控件 SlideMenuPanelLLayout 继承自ViewGroup。(继承ViewGroup则必须实现抽象方法onLayout())
★[其实也可以使用系统自带的 :android.support.v4.widget.SlidingPaneLayout ,它也是继承自ViewGroup的]
△[也可以使用第三方开源的自定义控件:例如:SlidingMenu]
▲【推荐使用Google官方推出的 DrawerLayout ,结合 Navigationview 】
65.:【免root 查看应用程序的 data/data/目录下的文件】
在AnroidManifest.xml中将 application节点下的 android:debuggable 属性设置为true; 否则,将无法在没有root权限的情况下查看应用的目录,会得到类似 permission denied的信息。
66.当应用进入后台且内存不足的时候,系统是会回收这个Activity的。通常我们都知道要用OnSaveInstanceState()去保存状态,用OnRestoreInstanceState()去恢复状态。
67.【建议在自定义的 BaseApplication 中提供一个 getAppContext() 方法。以后弹出Toast都可以用这个。】
public class BaseApplication extends Application {
private static BaseApplication mContext = null;
@Override
public void onCreate() {
super.onCreate();
mContext = this;
}
public static Context getAppContext() {
return mContext;
}
}
【注意】:使用Application提供的Context固然方便,但是有些时候不能使用Application的Context,不然会报错(比如startActivity(),显示Dialog等)。
【附】:调用 getResource() 方法时也建议使用Application的上下文。即:BaseApplication.getAppContext().getResources();;
在处理异常方面,UncaughtExceptionHandler可以对全局的异常进行捕获。测试崩溃可以使用Testin apm或bugly一些平台。
在Android中引用四大组件和Fragment这些重量级对象的时候要用WeakReference,常用的场景是static Handler持有Activity。
能用简单的布局就用简单的,特别是FrameLayout,它的layout_gravity属性非常好用。
BuildConfig.Debug可以判断是不是debug版本,可以通过它来控制一些调试代码,比如debug版本下打日志和测试服务器,release下不打日志,用正式服务器。
View可以getContext(),所以在设计方法的时候,参数中如果有View了就别搞Context这个参数了。View还可以post(),有view的时候就别new Handler().post()了。在给Handler发送消息的时候没必要每次都new Message(),而是使用handler.obtainMessage(),它会先看看消息队列里面有没有没用的消息,如果有可以复用消息对象。
如果是在应用范围内的广播可以使用LocalBroadcastManager这个API(低版本用v4下的),更加安全高效,不必担心别的app伪造广播或收听你的广播做一些不好的事情。
可以找一找你常用的app里面的开源许可,里面可以看到使用了哪些具体的开源项目。android开发一般都使用什么框架? - gzw1993 的回答最后,
善用Google和StackOverFlow,比百度和CSDN靠谱多了,比如想查下如何从代码中设置TextView的drawLeft属性,google搜索“android textview drawableLeft programmatically”即可,这是搜索到的第一条里面的内容:
-
android:animateLayoutChanges 这是一个非常酷炫的属性。
在父布局加上 android:animateLayoutChanges=“true” 后,如果触发了layout方法(比如它的子View设置为GONE),系统就会自动帮你加上布局改变时的动画特效!!
-
tools标签可以很好的帮助开发者实时预览xml的效果,
通过tools:background可以预览控件所占的控件,
tools:visibility可以把一个gone的控件在预览的时候展示出来,并且运行以后tools标签的内容不会展示出来.
例如:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:background="#FF00FF"
tools:visibility="visible"
tools:text="这段话只在预览时能看到,运行以后就看不到了" />
-
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE) 设置安全窗口,禁用系统截屏。
防止 App 中的一些界面被截屏,并显示在其他设备中造成信息泄漏。(常见手机设备系统截屏操作方式为:同时按下电源键和音量键。)
-
在RecycleViewAdapter的 onCreateViewHolder() 方法中,可以使用:
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
来获取 layoutInflater ,从而避免让 Adapter 持有Activity。
-
判断使用哪种Context :最简单的方法是根据控件(或组件)的生命周期决定传什么参数。
-
可以利用Application实现单进程的组件之间的数据传递。
通常情况下我们为了实现两个组件之间对象的传递,都需要将对象实现 Parcellable 或 Serializable 接口。但是如果两个Activity处于同一个进程,那么完全可以用Application 来实现。
-
当我们调用 getSharedPreference() 方法时实际上会将 磁盘文件中SharedPreference数据加载进内存中。
因此当我们访问某个保存在SharedPreference中的数据时,实际上会从内存缓存中获取,因此无需担心效率问题。
不过在往SharedPreference中写数据时就需要注意了:大多数情况下,我们使用 apply 就够了,因为 apply() 是同步写到内存,然后异步提交到磁盘,而 commit() 则是同步写入到内存,并且同步写入到磁盘。
-
Java 程序中判断当前线程是否是主线程可以用打印 Thread Name 的方式来分辨出主线程,而在Android程序中则有更简便的方法。
boolean isMainThread = (Looper.myLooper() == Looper.getMainLooper());
可以封装成一个工具方法:
public void checkWorkerThread() { boolean isMainThread = Looper.myLooper() == Looper.getMainLooper(); if (isMainThread) { if (BuildConfig.DEBUG) { throw new RuntimeException("Do not do time-consuming work in the Main thread"); } } }
-
判断当前程序是否运行在主进程
// 判断当前代码是否运行在主进程,如果是则返回true
private boolean isMainProcess() {
ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
String mainProcessName = getPackageName();
int myPid = Process.myPid(); // 获取当前进程id
for (ActivityManager.RunningAppProcessInfo info : processInfos) {
if (info.pid == myPid && mainProcessName.equals(info.processName)) {
return true;
}
}
return false;
} -
Jar和Aar的区别
Jar包里面只有代码,aar里面不光有代码还包括代码还包括资源文件,比如 drawable 文件,xml 资源文件。对于一些不常变动的 Android Library,我们可以直接引用 aar,加快编译速度
-
利用反射根据ActivityName 来开启Activity
Class c = Class.forName(ACTIVITY_NAME_TEMPLATE + Main + “Activity”);
Intent intent = new Intent(mActivityWeakRef.get().getApplicationContext(), c);
startActivity(intent); -
利用 Gson 实现反序列化,将json传解析成Bean对象时,Bean对象的类中定义的某个成员如果是String类型,则可以兼容json数据中的任何普通数据类型的数据。
例:
TestBean{
public String textSize;
}json { "textSize":14 }
此时依然能够将 14 注入到 TestBean.textSize 字段中。(最终的结果就是: textSize 内容为 “14”)
同理也能注入到一个Map<String,String> 中去:
例: 除了List<Map<String,Object>> , List<Map<String,String>> 也能容纳任何数据类型的json 属性值。 List<Map<String,String>> mapList = GsonUtil.fromJson(Base64Util.decrypt(newMenusData),new TypeToken<List<Map<String,String>>>(){}.getType());
-
[通过包名实际上就可以开启手机上所有的App]
- 如果只是打开这些程序,那么可以利用桌面图标的启动方式,只需利用【包名】就可以开启桌面的任意应用程序!
注意: 打开前需要判断指定包名所对应的应用程序,是否存在
//例: 利用包名打开支付宝
PackageManager packageManager = this.getApplicationContext().getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage("com.eg.android.AlipayGphone");
startActivity(intent);
更多详见: …\android 开发\Intent\隐式意图 与 显示意图.txt