这些小技巧


通过上面的这些文章,就把简单的安卓项目总结了一遍,当然你说懂这些就可以做Android开发的话还是不行的,欠缺的还有很多,但欠缺的这些我们有只能在工作中去总结以及不断的提高,这篇文章我们还有一些小技巧需要我们总结一下,然后在后面准备做一个完整的实验项目,让我们把学的这些串联起来,这篇我们将说说下面这些技巧:

      一、获取全局Context

      二、使用Intent传递对象

  1、Serializable方式

2、Parcelable方式

三、日志控制

      四、创建定时任务

  五、聊聊Doze模式

      六、多窗口

      七、禁止多窗口模式

八、lambda表达式    这个表达式是JAVA 8 的新特性,我们直接在后面完整的Demo中使用,用到的时候再具体的说明

获取全局Context


这里我们考虑这样一个问题,我们再一个类中进行了一些异步操作,完了之后我们需要一个Toast提示,这时候我们需要Context,那我们有那么获取Context。

首先就有这样一种,我们直接在初始化这个类的时候传递一个Context,的确这样是能解决问题的,但这不是最好的解决问题的办法,最好的办法是我们获取一个全局的Context,下面我们总结如何获取一个全局的Context。

  1. package com.example.skotc.servicedemo;
  2.  
  3. import android.app.Application;
  4. import android.content.Context;
  5. /**
  6. * Created by skotc on 2018/8/20.
  7. */
  8. public class MyApplication extends Application {
  9.  
  10. private static Context context;
  11. @Override
  12. public void onCreate() {
  13. super.onCreate();
  14.  
  15. context = getApplicationContext();
  16. }
  17. public static Context getContext() {
  18. return context;
  19. }
  20. }

上面的代码我们就创建了一个MyApplication继承自Application,然后再以后的使用中我们就可以直接调用这个方法得到全局的Context, MyApplication.getContext()方法获取得到Context。

还有一点需要我们注意一下的,就是在创建了MyApplication之后我们还是需要在AndroidManifest.xml中声明一下。具体的代码如下,主要的就是这句: android:name=".MyApplication"

  1. <application
  2. android:allowBackup="true"
  3. android:icon="@mipmap/ic_launcher"
  4. android:label="@string/app_name"
  5. android:supportsRtl="true"
  6. android:theme="@style/AppTheme"
  7. android:name=".MyApplication"
  8. >
  9. <activity
  10. android:name=".ServiceMainActivity"
  11. android:label="@string/app_name"
  12. android:theme="@style/AppTheme.NoActionBar">
  13. <intent-filter>
  14. <action android:name="android.intent.action.MAIN" />
  15. <category android:name="android.intent.category.LAUNCHER" />
  16. </intent-filter>
  17. </activity>
  18. </application>

使用Intent传递对象


Intent相信我们都比较熟悉了,我们可以使它来启动活动,发送广播,启动广播等,在进行上述操作的时候,我们还可以在Intent中添加一些附加数据,已达到传值的效果,比如我们见过的调用 putExtra(键,值)方法来添加要传递的数据,之后通过调用 getIntent().getStringExtra(键)来获取我们传递的值,通过这种方法我们能传递的对象类型是有限的,也就常见的类型,那我们有没有想过,要是需要专递的是一个自定义的对象的时候呢,我们该怎样做?

下面我们就讨论一下这个问题:

1、Serializable方式 (序列化)

Serializable是序列化的意思,表示将一个对象转换成可存储或者可传输的状态,序列化后的对象可以在网络上进行传输,也可以存储在本地,至于序列化的方法也是很简单,只需要让一个类去实现Serializable接口就可以。

比如我们实现了一个person类,让它实现Serializable接口:

  1. class person implements Serializable{
  2.  
  3. private String name;
  4. private int age;
  5.  
  6. public void setName(String name) {
  7. this.name = name;
  8. }
  9.  
  10. public void setAge(int age) {
  11. this.age = age;
  12. }
  13.  
  14. public String getName() {
  15. return name;
  16. }
  17.  
  18. public int getAge() {
  19. return age;
  20. }
  21. }

接下来我们看看这个自定义对象的传递以及获取:

  1. person zhangxu = new person();
  2. zhangxu.setAge(18);
  3. zhangxu.setName("tiancia");
  4.  
  5. //传递
  6. Intent intent = new Intent(ServiceMainActivity.this,SecondActivity.class);
  7. intent.putExtra("person", zhangxu);
  8. startActivity(intent);
  9. // 获取
  10. person zhangxu2 = (person) getIntent().getSerializableExtra("person");

一句话总结:我们之所以能将我们自定义的类在Intent中传递就是因为我们自定义为类实现了 Serializable 接口。

Parcelable


Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都将是 Intent 所支持的数据类型,这样也就实现传递对象的功能。

接下来我们修改我们的额person类,修改这个类的注意事项我们在代码中都有加注释

  1. /*
  2. *
  3. * 实现Parcelable接口
  4. * 就要重写里面的两个方法
  5. * describeContents
  6. * writeToParcel
  7. *
  8. * */
  9.  
  10. class person implements Parcelable{
  11.  
  12. private String name;
  13. private int age;
  14.  
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18.  
  19. public void setAge(int age) {
  20. this.age = age;
  21. }
  22.  
  23. public String getName() {
  24. return name;
  25. }
  26.  
  27. public int getAge() {
  28. return age;
  29. }
  30.  
  31. @Override
  32. public int describeContents() {
  33. return 0;
  34. }
  35.  
  36. // 把数据写入到parcel中
  37. @Override
  38. public void writeToParcel(Parcel parcel, int i) {
  39.  
  40. parcel.writeString(name);
  41. parcel.writeInt(age);
  42.  
  43. }
  44.  
  45. // 我们还必须在person类中创建一个CREATOR常量,这里创建了一个Parcelable.Creator接口的实现
  46. // 并且将泛型类型指定为person,接着重写里面的两个方法
  47. // createFromParcel 这个方法中读取刚才存入的字段
  48. // newArray
  49. public static final Parcelable.Creator<person>CREATOR = new Parcelable.Creator<person>(){
  50.  
  51. @Override
  52. public person createFromParcel(Parcel parcel) {
  53. person person = new person(); // 读取数据
  54. person.name = parcel.readString();
  55. person.age = parcel.readInt();
  56. return person;
  57. }
  58.  
  59. @Override
  60. public person[] newArray(int i) {
  61. return new person[i];
  62. }
  63. };
  64. }

说说它的传递方式,传入时候和我们之前写的Serializable是一样的,就不在重复,只是在读取的时候,有一点需要我们注意一下,就是方法名改变了:

  1. person zhangxu3 = (person) getIntent().getParcelableExtra("person");

它们俩的区别:

serializable的方式比较简单,但由于会把整个对象进行序列化,因此效率会比Parcelable低一些,所以在通常情况下我们还是建议使用Parcelable方式!

日志控制


在iOS中我们经常有用到这个日志控制的问题,在安卓中也是,就是在debug阶段我们需要大量的日志,但是在release状态我们是不需要的,日志不仅仅会增加程序运行的成本,还会泄漏一些重要的信息,所以在编译release状态我们是需要控制日志打印的,在安卓中我们可以写这样的一个类来进行处理。

  1. class LogUntil{
  2.  
  3. public static final int VERBOSE = 1;
  4. public static final int DEBUG = 2;
  5. public static final int INFO = 3;
  6. public static final int WARN = 4;
  7. public static final int ERROR = 5;
  8. public static final int NOTHING = 6;
  9. public static final int leven = VERBOSE;
  10.  
  11. public static void v(String tag,String msg){
  12.  
  13. if (leven<=VERBOSE){
  14. Log.d(tag,msg);
  15. }
  16. }
  17. public static void d(String tag,String msg){
  18.  
  19. if (leven<=DEBUG){
  20. Log.d(tag,msg);
  21. }
  22. }
  23. public static void i(String tag,String msg){
  24.  
  25. if (leven<=INFO){
  26. Log.d(tag,msg);
  27. }
  28. }
  29. public static void w(String tag,String msg){
  30.  
  31. if (leven<=WARN){
  32. Log.d(tag,msg);
  33. }
  34. }
  35. public static void e(String tag,String msg){
  36.  
  37. if (leven<=ERROR){
  38. Log.d(tag,msg);
  39. }
  40. }
  41. }

上面的这段代码就是我们常用的日志控制,在我们要发布的时候,我们设置leven的值为NOTHING的时候我们的日志也就不见了!和我们iOS的理解方式是一样的,我们iOS中会用到DEBUG这个变量,具体的我也就不再多说了,有兴趣的可以自己找找这方面的问题,我们直说安卓的。

创建定时任务


在Android中,实现定时器的任务是有两种方式的,一种是使用Java API 提供的Timer类,一种是使用Android的Alarm机制,这令中方式在大多数情况下都能实现类似的效果,但是Timer有一个致命的短板,它并不适用于那些长期在后台运行的定时器任务,我们都知道为了能让电池更加耐用,每一种手机都会有自己的休眠策略,Android手机在长时间不操作的情况下会让CPU处于睡眠状态,就会导致Timer中的定时器任务无法正常运行,而Alarm则具有唤醒CPU的功能,它保证在大多数情况下需要执行任务的时候CPU都能正常运行。这里需要注意唤醒CPU和唤醒屏幕完全不是同一个概念!不要混淆。

下面我们用代码写一个Alarm的实际例子:

  1. class LongRunningService extends Service{
  2.  
  3. @Nullable
  4. @Override
  5. public IBinder onBind(Intent intent) {
  6. return null;
  7. }
  8.  
  9. @Override
  10. public int onStartCommand(Intent intent, int flags, int startId) {
  11. new Thread(new Runnable() {
  12. @Override
  13. public void run() {
  14.  
  15. }
  16. }).start();
  17.  
  18. // 获取AlarmManager对象
  19. AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);
  20. // 一个小时的毫秒数
  21. int anHour = 60*60*1000;
  22. // SystemClock.elapsedRealtime方法表示系统开机至今经历的毫秒数
  23. // SystemClock.currentTimeMillis方法表示获取1970年1月1日零时至今所经历的毫秒数
  24. long triggerAtTime = SystemClock.elapsedRealtime()+anHour;
  25.  
  26. // 指定处理定时任务的服务为LongRunningService 最后在调用set方法
  27. Intent i = new Intent(this,LongRunningService.class);
  28. PendingIntent pendingIntent = PendingIntent.getService(this,0,i,0);
  29.  
  30. //AlarmManager.ELAPSED_REALTIME_WAKEUP 表示让定时任务的触发时间从系统开机算起,但是会唤醒CPU
  31. //AlarmManager.ELAPSED_REALTIME 表示让定时任务的触发时间从系统开机算起,但是不会唤醒CPU
  32. //AlarmManager.RTC 表示让定时任务的触发时间从1970,1,1算起,但是不会唤醒CPU
  33. //AlarmManager.RTC_WAKEUP 表示让定时任务的触发时间从1970,1,1算起,但是会唤醒CPU
  34. //triggerAtTime 时间
  35. manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pendingIntent);
  36. return super.onStartCommand(intent, flags, startId);
  37. }
  38. }

聊聊Doze模式


我们说说这个Doze模式,说说到底什么是Doze模式。当用户的设备是6.0或者以上系统的时候,如果该设备没有接电源,且并木关闭了一段时间之后,就会进入Doze模式。在Doze模式下,系统会对CPU,网络,Alarm等活动进行限制,从而延长电池的使用寿命。当然系统也不会一直处于Doze模式,而是间接性的退出Doze模式一小段时间,而在这一下欧丹时间中,应用就可以完成他们的同步操作,Alarm任务等等,

接下来看看在Doze模式下那些功能会受到影响:

1、网络访问被限制

2、系统忽略唤醒CPU或者屏幕操作

3、系统不再执行WIFI扫描

4、系统不再执行同步服务

5、Alarm任务将会在下次退出Doze模式的时候执行

多窗口


Android在7.0之后导入了多窗口模式,在这里我们可以大概的学习一下多窗口模式。

在这里我们说一下,在多窗口模式下并不会改变活动原有的生命周期,只是会将用户最近交互过的那个活动设置为运行状态,而将多窗口模式下另外一个可见的活动设置为暂停状态,如果这时候用户又和暂停的活动进行交互,那么该活动就会进入运行状态,之前处于运行状态的活动变成暂停状态。

前面我们说到在多窗口模式下,活动的生命周期是不会发生改变的,那么有一些问题我们就可以随之考虑一下:

比如说,在多窗口模式下,用户任然处于可以看到暂停状态的应用,那么像视频播放之类的应用在此时就应该是继续播放视频才对,因此,我们最好不要在活动的onPause方法中处理视频播放器的暂停逻辑,而是应该在onStop()方法中处理,并且在onStart方法中回复视频的播放。

另外,针对进入多窗口模式时候,活动会被重新创建,如果你想改变这一默认行为,可以在 Androidmainfest.xml中进行如下配置:

  1. <activity
  2. android:name=".SecondActivity"
  3. android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
  4. ></activity>

加入这个配置之后,不管是进入多窗口模式,还是横竖屏切换,活动都不会被重新创建,而是会将屏幕发生变化的事件通知到Activity的onConfigurationChanged()方法中,所以你要是想在屏幕发生改变的时候进行相应的逻辑处理,那么在活动中重写onConfigurationChanged()方法即可。

禁止多窗口模式


上面我们说了一些关于多窗口模式的一些问题,现在我们再想一个场景,如果我们做的是游戏,要是进入了多窗口模式是不是很尴尬,总不是一边发微信一遍玩游戏的吧,看着自己GG,当然我们也有办法避免应用进入多窗口模式,禁止的方式也很简单:

Androidmainfest.xml 中这样配置:

android:resizeableActivity="false"  true表示支持,false表示禁止

这样就OK了吗?其实还有一个问题需要我们考虑一下这个问题,这个属性是在我们指定 targetSdkVersion 大于等于24的时候才有效的,那小于24呢?没有这个属性我们怎么处理呢?我们再这里说一种解决方案:

Android规定,如果项目指定的targetSdkVersion低于24,并且活动是不允许横竖屏切换的,那么该应用也将不支持多窗口模式。

默认情况下,我们的应用是支持横竖屏切换的,如果想想要让应用不允许横竖屏切换,那么就需要在 Androidmainfest.xml的<activity>标签中加如下配置:

其中 portrait 表示竖屏   landscape 表示横屏

  1. android:screenOrientation="portrait"

Android学习--还有一些小技巧的更多相关文章

  1. Android开发效率的小技巧

    提高eclipse使用效率(二) 提高Android开发效率的小技巧   XML文件的代码提示 adt中也有xml文件的代码提示,为了让提示来的更加猛烈,我们还要设置一下 打开eclipse - Wi ...

  2. Android——Android Studio的一些小技巧(转)

    ndroid课程---Android Studio的一些小技巧   APK瘦身 在Android Studio中我们可以开启混淆,和自动删除没有Resources文件,来达到给APP瘦身的目的,这对于 ...

  3. 牛腩新闻公布系统--学习Web的小技巧汇总

    2014年11月10日,是个难忘的日子.这一天.小编的BS学习開始了.BS的开头,从牛腩新闻公布系统開始.之前学习的内容都是CS方面的知识,软考过后.開始学习BS,接触BS有几天的时间了,跟着牛腩老师 ...

  4. 牛腩新闻发布系统--学习Web的小技巧汇总

    2014年11月10日,是个难忘的日子,这一天,小编的BS学习开始了,BS的开头,从牛腩新闻发布系统开始,之前学习的内容都是CS方面的知识,软考过后,开始学习BS,接触BS有几天的时间了,跟着牛腩老师 ...

  5. Android——隐藏输入法的小技巧

    今天偶然在百度地图提供的DEMO里看到这样一段代码.认为确实是个小技巧,就写下来分享一下. 针对的问题: 我们在开发android界面的时候,常常使用EditText控件.然后每次进入这个页面的时候, ...

  6. Android学习笔记之布局技巧以及布局中的细节介绍....

    PS:休息两天,放一放手上的东西,做做总结... 学习内容: 1.Android中LinearLayout布局技巧... 2.layout中drawable属性的区别...   先简单的介绍一下dra ...

  7. Android课程---Android Studio的一些小技巧

    APK瘦身 在Android Studio中我们可以开启混淆,和自动删除没有Resources文件,来达到给APP瘦身的目的,这对于一些维护很久的老项目比较有用,里面有很多无效的Resource, 删 ...

  8. Android开发中的小技巧

    转自:http://blog.csdn.net/guxiao1201/article/details/40655661 简单介绍: startActivities (Intent[] intents) ...

  9. 提高eclipse使用效率(二) 提高Android开发效率的小技巧

    XML文件的代码提示 adt中也有xml文件的代码提示,为了让提示来的更加猛烈,我们还要设置一下 打开eclipse - Window - Preferences,在右边的目录树中切换到XML - X ...

随机推荐

  1. 【转】Visio画用例模型图竟然没有include关系

    转自:http://blog.csdn.net/shuixin536/article/details/8289746 由于电脑上没有安装Rose,因此决定用visio来画UML中的用例模型图,在绘制的 ...

  2. 【题解】ZJOI2008骑士

    树型打牌:洛谷P2607 这道题目一开始没有想到解法,只是想到没有上司的舞会,觉得十分的类似呀. 之后发现:n个点,n条边,只要删去一条边,就变成了和上题一模一样的做法. 那么考虑删去的这条边,实际上 ...

  3. Winpcap网络开发库入门

    原文链接地址:http://www.cnblogs.com/phinecos/archive/2008/10/20/1315176.html Winpcap是一个强大的网络开发库,可以实现许多功能:获 ...

  4. Kd-tree题表

    bzoj1941: [Sdoi2010]Hide and Seekbzoj2626: JZPFARbzoj4520: [Cqoi2016]K远点对bzoj2989: 数列bzoj2850: 巧克力王国 ...

  5. JUnit4.11 理论机制 @Theory 完整解读

    最近在研究JUnit4,大部分基础技术都是通过百度和JUnit的官方wiki学习的,目前最新的发布版本是4.11,结合代码实践,发现官方wiki的内容或多或少没有更新,Theory理论机制章节情况尤为 ...

  6. 一个JavaScript反射使用的例子

    反射机制指的是程序在运行时能够获取自身的信息.例如一个对象能够在运行时知道自己有哪些方法和属性.在JavaScript中有一个很方便的语法来实现反射,即for(…in…)语句,其语法如下: 1 for ...

  7. Reasons to use innodb_file_per_table

    When working with InnoDB, you have two ways for managing the tablespace storage: Throw everything in ...

  8. activity栈清空

    http://blog.csdn.net/swjtuxu/article/details/26163737

  9. 2015年网易校招Java开发工程师(技术架构)在线笔试题

    1.  程序和进程的本质区别是? A.在外存和内存存储 B.非顺序和顺序执行机器指令 C.独占使用和分时使用计算机资源 D.静态和动态特征 参考答案分析: 进程与应用程序的区别: 进程(Process ...

  10. jquery中:input和input的区别

    :input表示选择表单中的input,select,textarea,button元素, input仅仅选择input元素. <button>和<input type=" ...