Android基础知识——你还应该掌握的高级技巧

Stella981
• 阅读 601

文章目录

  • 1.全局获得Context的技巧
  • 2.使用Intent传递对象
    • 2.1Serializable方式
    • 2.2Parcelable方式
  • 3.定制自己的日志工具
  • 4.创建定时任务
    • 4.1Alarm机制
    • 4.2Doze模式
  • 5.多窗口模式编程
    • 5.1多窗口模式下的生命周期
    • 5.2禁用多窗口模式

1.全局获得Context的技巧

在我们学习Android基础知识的时候,你会发现在很多地方我们都会使用到Context,弹出Toast的时候需要,启动活动的时候需要,发送广播的时候需要,操作数据库的时候需要,使用通知的时候需要,等等等等。所以有时候在需要使用Context时,却不知道该怎么获得Context将会是一件非常伤脑筋的事情。本节我们就来介绍一个全局获得Context的技巧。

使用步骤:

1.新建类继承Application类,在其中获取Context并定义一个用于外部获取Context的方法。
2.给AndroidManifest.xml设置android:name属性。也就是告知系统,当程序启动时应该初始化MyApplication类,而不是默认的Application类。

示例:

//步骤一
public class MyApplication extends Application {
   
   
    private static Context context;

    @Override
    public void onCreate() {
   
   
        super.onCreate();
        context=getApplicationContext();
    }

    public static Context getContext(){
   
   
        return context;
    }
}
//步骤二
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.temp">

    <application
        android:name=".MyApplication"//告知系统当程序启动时初始化MyApplication类
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

这里还有个小问题:在我们学习LitePal时我们也需要设置AndroidManifest.xml中的android:name属性,那当你两者都想要使用时该怎样处理呢?其实解决方法也很简单,我们只需在我们自己的Application中调用LitePal的初始化方法即可。

示例:

public class MyApplication extends Application {
   
   
    private static Context context;

    @Override
    public void onCreate() {
   
   
        super.onCreate();
        context=getApplicationContext();
        LitePal.initialize(context);
    }

    public static Context getContext(){
   
   
        return context;
    }
}

2.使用Intent传递对象

Intent传递基础类型的数据相信你已经比较熟悉了,可是如果我们想要用Intent传递一个对象的话那该怎样处理呢?本节我们就来学习一下使用Intent传递对象。

2.1Serializable方式

使用步骤:

1.定义一个你想要传递的类,并让该类继承Serializable接口。
2.调用putExtra()方法向Intent中存储对象,调用getSerializableExtra()方法从Intent中获取对象。

Serializable详解:Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。

示例:

//步骤一
public class Student implements Serializable {
   
   
    String name;
    int age;

    public Student(String name,int age){
   
   
        this.name=name;
        this.age=age;
    }
}
//步骤二
public class MainActivity extends AppCompatActivity {
   
   

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
   
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button=(Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
   
   
            @Override
            public void onClick(View view) {
   
   
                Intent intent=new Intent(MainActivity.this,MainActivity2.class);
                Student student=new Student("Tom",18);
                intent.putExtra("Student",student);//向Intent中存储对象
                startActivity(intent);
            }
        });
    }
}

public class MainActivity2 extends AppCompatActivity {
   
   

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        Intent intent=getIntent();
        Student student= (Student) intent.getSerializableExtra("Student");//从Intent中获取对象
        Toast.makeText(MainActivity2.this,student.name,Toast.LENGTH_SHORT).show();
    }
}

2.2Parcelable方式

使用步骤:

1.定义一个你想要传递的类,让其继承Parcelable接口并实现接口中的一些方法。
2.调用putExtra()方法向Intent中存储对象,调用getParcelableExtra()方法从Intent中获取对象。

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

示例:

//步骤一
public class Student implements Parcelable {
   
   
    String name;
    int age;

    public Student(){
   
   
    }

    public Student(String name,int age){
   
   
        this.name=name;
        this.age=age;
    }

    public static final Creator<Student> CREATOR = new Creator<Student>() {
   
   
        @Override
        public Student createFromParcel(Parcel in) {
   
   
            Student student=new Student();
            student.name=in.readString();//读取name(注意这里的读取顺序要和写入顺序完全相同)
            student.age=in.readInt();//读取int
            return student;
        }

        @Override
        public Student[] newArray(int size) {
   
   
            return new Student[size];
        }
    };

    @Override
    public int describeContents() {
   
   
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
   
   
        parcel.writeString(name);//写出name
        parcel.writeInt(age);//写出age
    }
}
//步骤二
public class MainActivity extends AppCompatActivity {
   
   

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
   
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button=(Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
   
   
            @Override
            public void onClick(View view) {
   
   
                Intent intent=new Intent(MainActivity.this,MainActivity2.class);
                Student student=new Student("Tom",18);
                intent.putExtra("Student",student);//向Intent中存储对象
                startActivity(intent);
            }
        });
    }
}

public class MainActivity2 extends AppCompatActivity {
   
   

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        Intent intent=getIntent();
        Student student= (Student) intent.getParcelableExtra("Student");//从Intent中获取对象
        Toast.makeText(MainActivity2.this,student.name,Toast.LENGTH_SHORT).show();
    }
}

3.定制自己的日志工具

现在让我们设想一个场景,你正在编写一个比较庞大的项目,期间为了方便调试,在代码的很多地方都打印了大量的日志。最近项目已经基本完成了,但是却有一个非常令人头痛的问题,之前用于调试的那些日志,在项目正式上线之后仍然会照常打印,这样不仅会降低程序的运行效率,还有可能将一些机密性的数据泄露出去。那可能会有人说我把打印日志的代码一行一行全部删掉就行了,这显然不是什么好点子,不仅费事费力,而且以后你继续维护这个项目时可能还会需要这些日志。本节我们就来学习该如何优雅的解决这个问题。

解决方法:

事实上这个问题的解决方法非常简单,我们只需要定义一个自己的日志工具,并在里面对打印日志条件加上限制条件即可。

示例:

public class LogUtil {
   
   

    private static final int VERBOSE=1;
    private static final int DEBUG=2;
    private static final int INFO=3;
    private static final int WARN=4;
    private static final int ERROR=5;
    private static final int NOTHING=6;
    private static int level=VERBOSE;//我们只需要更改level的值即可对不同等级的打印语句进行限制,而当我们不想打印任何日志时,我们只需将level的值设置为NOTHING即可。

    public static void v(String tag,String msg){
   
   
        if(level<=VERBOSE){
   
   
            Log.v(tag,msg);
        }
    }

    public static void d(String tag,String msg){
   
   
        if(level<=DEBUG){
   
   
            Log.d(tag,msg);
        }
    }

    public static void i(String tag,String msg){
   
   
        if(level<=INFO){
   
   
            Log.i(tag,msg);
        }
    }

    public static void w(String tag,String msg){
   
   
        if(level<=WARN){
   
   
            Log.w(tag,msg);
        }
    }

    public static void e(String tag,String msg){
   
   
        if(level<=ERROR){
   
   
            Log.e(tag,msg);
        }
    }
}

4.创建定时任务

Android中的定时任务一般有两种实现方式,一种是java API里提供的Timer类,一种是使用Android的Alarm机制。而两者的区别在于:Android手机会在长时间不操作的情况下自动让CPU进入到睡眠状态,这就有可能导致Timer中的定时任务无法正常运行,而Alarm则具有唤醒CPU的功能。(这里要注意唤醒CPU和唤醒屏幕完全是两个概念)

4.1Alarm机制

使用步骤:

1.获取AlarmManager实例。
2.调用manager.set()方法创建定时任务。

示例:

public class MainActivity extends AppCompatActivity {
   
   

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
   
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button=(Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
   
   
            @Override
            public void onClick(View view) {
   
   
                Intent intent=new Intent(MainActivity.this,MainActivity2.class);
                PendingIntent pendingIntent=PendingIntent.getActivity(MainActivity.this,0,intent,0);
                AlarmManager alarmManager= (AlarmManager) getSystemService(ALARM_SERVICE);//步骤一
                long time= SystemClock.elapsedRealtime()+1000;
                alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,time,pendingIntent);//步骤二
            }
        });
    }
}

manager.set()方法详解:第一个参数同于设置工作类型,ELAPSED_REALTIME型:表示定时任务的触发时间从系统开机开始算起,但不会唤醒CPU;ELAPSED_REALTIME_WAKEUP类型:表示定时任务的触发时间从系统开机开始算起,且会唤醒CPU;RTC类型:表示定时任务的触发时间从1970年1月1日0点开始算起,但不会唤醒CPU;RTC_WAKEUP类型:表示定时任务的触发时间从1970年1月1日0点开始算起,且会唤醒CPU。第二个参数就是定时任务的触发时间,以毫秒为单位(注意要与第一个参数相匹配)。第三个参数就是定时调度任务要执行的具体事件了。

注意:从Android4.4系统开始,Alarm任务的触发事件会变得不准确,有可能会延迟一段时间后才会执行,当然这可不是Bug,这只是为了能让手机更好的节省电量。但倘若你要求Alarm任务的执行时间必须准确无误,那么你只需将set()方法更改为setExact()方法即可。

4.2Doze模式

Doze模式是Android6.0系统新加入的一种省电模式。该模式下系统会对CPU,网络,Alarm等活动进行限制,从而延长电池的使用寿命。因此这种模式也就极大的影响了我们Alarm任务的执行时间。不过倘若你真的有非常特殊的需求,要求在Doze模式下Alarm任务也要必须正常执行,Android还是提供了解决方案的。我们只需调用AlarmManger的setAndAllowWhileIdle()或setExactAndAllowWhileIdle()方法即可让你的Alarm任务在Doze模式下也能正常执行了。

5.多窗口模式编程

多窗口模式也就是我们现在经常说的分屏模式了。

5.1多窗口模式下的生命周期

当一个活动进入多窗口模式或横竖屏切换时,该活动会重新创建。多窗口模式下正在与用户交互的活动处于onResume状态,另一个则处于onPause状态。

另外,针对于进入多窗口模式时活动就会被重现创建,如果你想改变这一默认行为,只需在AndoridManifest.xml文件中进行如下配置即可:

<activity android:name=".MainActivity"
    android:configChanges="orientation|keyboardHidden|screenSize|screenLayout">

加入了这行配置之后,不管是进入多窗口模式,还是横竖屏切换,活动都不会被重新创建,而是会将屏幕发生改变的事件通知到Activity的onConfigurationChanged()方法当中。

5.2禁用多窗口模式

禁用多窗口模式的方法非常简单,只需在AndroidManifest.xml的< application >或< activity >标签下加入如下属性即可:

android:resizeableActivity=["true"|"false"]

其中,true表示应用支持多窗口模式,false表示应用不支持多窗口模式,该属性默认为true。

不过上面的方法只能在targetSdkVersion为24以上时才会有用,否则这个属性是无效的。不过Android规定,当targetSdkVersion为24以下,并且活动不允许横竖屏切换,那么该应用也将不支持多窗口模式。配置方法如下:

android:screenOrientation=["portrait"|"landscap"]

其中,portrait表示活动只支持竖屏,landscap表示活动只支持横屏。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这