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

Posted ABded

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android基础知识——你还应该掌握的高级技巧相关的知识,希望对你有一定的参考价值。

文章目录

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表示活动只支持横屏。

以上是关于Android基础知识——你还应该掌握的高级技巧的主要内容,如果未能解决你的问题,请参考以下文章

android开发零基础入门教程

【Camera专题】Qcom-你应该掌握的Camera调试技巧2

python面试必备:掌握这三个技巧,你还怕找不到工作?

Android高级UI之Canvas深度分析—变换技巧,状态保存

掌握这9个单行代码技巧!你也能写出『高端』Python代码 ⛵

14 个实用的数据库设计技巧,哪些你还不知道?