安卓基础学习笔记(七)

/ 0评 / 0

1.详细描述“内部类”的概念
【定义】
在某个类的内部,再定义的类,则称之为内部类,而内部类的属主类,称之为该内部类的外部类。
【种类】
成员内部类:作为另一个类的成员出现的内部类,例如:

public class OutterClass {
  private class InnerClass {
    public void test() {
      System.out.println(name);
    }
  }
  
  private String name;
  
  public void run() {}
}

成员内部类可以使用任何访问权限修饰符进行修饰。
成员内部类可以访问外部类的所有成员,包括私有的。
成员内部类不可以直接创建对象,如果需要创建对象,必须先创建其外部类的对象。

局部内部类:在方法的内部定义的内部类称之为局部内部类。

public class OutterClass {
  public void run() {
    int x = 10;
    final int y = 10;
    
    class InnerClass {
      public void test() {
        // System.out.println(x); // 错误
        System.out.println(y); // 正确
      }
    }
    
    InnerClass ic = new InnerClass();
  }
}

局部内部类不可以使用任何访问权限修饰符进行修饰,因为访问权限修饰符只能修饰类的成员。
局部内部类的定义、使用必须遵循语法的执行顺序。
局部内部类中,不可以直接访问局部变量,如果一定需要访问,应该将局部变量使用final进行修饰,使之成为常量,或者,将该局部变量提升为全局变量。

public class MainActivity extends Activity {
  protected void onCreate(Bundle bundle) {
    String name = etUsername.getText().toString();
  
    class InnerOnClickListener implements OnClickListener {
      @Override
      public void onClick(View v) {
        // Toast.make(MainActivity.this, name, 0).show(); // 错误
      }
    }
    
    InnerOnClickListener l = new InnerOnClickListener();
    btnOk.setOnClickListener(l);
  }
}

匿名内部类:直接创建已知的类的子类对象,或创建已知的接口的实现类对象,这样的内部类称之为匿名内部类,例如:

public class MainActivity extends Activity {
  protected void onCreate(Bundle bundle) {
    int x = 10;
    final int y = 10;
  
    new Thread() {
      @Override
      public void run() {
        // System.out.println(x); // 错误
        System.out.println(y); // 正确
      }
    };
  
    OnClickListener listener = new OnClickListener() {
      @Override
      public void onClick(View v) {
      
      }
    };
    
    btnOK.setOnClickListener(listener);
    btnCancel.setOnClickListener(listener);
  }
}

由于匿名内部类是在定义该类时就直接创建了对象,所以,匿名内部类只能创建1个对象。
在绝大部分应用场景中,匿名内部类是在方法中出现的,所以,这样的匿名内部类具有局部内部类的特性。

静态内部类:也可以称之为静态成员内部类,这样的内部类是使用static修饰的内部类,而static关键字只能用于修饰类的成员。

public class OutterClass {
  private static String name;
  private int x;
  
  public void run() {}
  
  private static class InnerClass {
    public void test() {
      System.out.println(name); // 正确
      // System.out.println(x); // 错误
    }
  }
}

静态内部类只能访问外部类的其它静态成员,而不可以直接访问非静态成员。
静态内部类可以直接创建对象,无须依赖于外部类的对象。

2. 描述“抽象”与“接口”的概念
可以使用abstract关键字修饰类或方法,被修饰的类称之为抽象类,被修饰的方法称之为抽象方法。
抽象方法没有方法体,且必须存在于抽象类中,例如:

public abstract class Shape {
  public abstract void draw();
}

抽象类中的方法并不一定是抽象方法,甚至抽象类中可以没有抽象方法,例如:

public abstract class Shape {
  public void draw() {
    System.out.println("do something.");
  }
}

由于抽象类中可能存在抽象方法,而抽象方法并没有被具体的实现,所以,抽象类被认为是“不完整的”,抽象类不可以直接创建对象,但是仍然有构造方法,且在创建其子类的对象时,该构造方法会被调用。
如果某个类继承自抽象类,则有义务重写该类中的抽象方法,除非该子类也是抽象的。
从一定程度上而言,“抽象类的作用就是用于被继承的”。
注意:“接口是一种极端的抽象类”,这个说法是错误的!
接口的所有成员都是public的。
接口的所有属性都是static final的。
接口的所有方法都是abstract的。
类与接口的关系是“实现”的关系,使用implements关键字。
一个类可以同时实现多个接口。
接口与接口之间可以存在“继承”关系,使用extends关键字,且一个接口可以同时继承多个接口。
类通常用于“类别”的概念,而接口通常用于约定规范、标准,或者定制行为模式。

3.详细描述“多态”的概念
多态是面向对象的三大特征之一。表现为某个对象在编译期和运行期表现为不同的形态。
从语法上,多态表现为:使用父级的数据类型声明,创建出子级的对象,例如:
Animal a = new Huskie();
以上语法的表现形式也称之为“向上转型”。
对象经过向上转型后,只能调用父级(声明时的)类型已经声明的属性、方法,而不可以再调用自身类型特有的属性、方法。
如果一定需要调用子类特有的属性、方法,则需要向下转型,向下转型直接使用强制类型转换的语法即可,例如:
Dog d = (Dog) a;
向下转型的前提是该对象曾经向上转型过,即对象的本质是与向下转型时声明的类型是匹配的。
为了保证向下转型不会出现类型转换异常(ClassCastException),可以使用instanceof关键字对数据类型进行判断,例如:
a instanceof Huskie -> true
a instanceof Dog -> true
a instanceof Object -> true
凡是应用了多态后,当调用对象的方法时,如果子类重写过,则会执行子类重写后的方法。
关于多态的应用,可以小结为:凡是需要父级类型的对象(声明为父级),都可以使用子级类型的对象。
多态的应用,也适用于接口与接口的实现类。

4. 详细描述“异常”的概念
异常的体系结构中,最顶端的是Throwable,其直接子级有Error和Exception,其中,Error表示的是“错误”,Exception表示的是“异常”。
异常主要区分为RuntimeException和其它Exception。
其它Exception都是必须处理的,处理的方式主要有:
1) 使用try...catch包裹代码
2) 使用throws在方法体上声明抛出
凡是RuntimeException,都可以不用处理,也可以不用遵守处理异常的规则。

练手项目:音乐播放器
---------------------------------
【目标】
实现使用Service播放歌曲,使用Activity完成UI部分,包括UI的创建、初始化、响应等。
【实现步骤】
一、设计界面
1、activity_main从上至下分为3个区域,分别是:
1) ListView列表
2) 歌曲信息显示部分:歌曲标题、进度条、当前播放到的时间、歌曲的总时长
3) 歌曲播放控制区域:播放/暂停、上一首、下一首
2、设计ListView的item,即模版
3、获取歌曲列表的数据
1) 声明Music类型,即创建Music.java,在该类中至少声明歌曲标题(title)和路径(path)属性
2) 获取歌曲数据,逻辑参照V1.0版本
4、创建MusicAdapter
5、在Activity中完成ListView的显示
二、封装播放功能
1. 创建PlayMusicService类,继承自Service,并注册
2. 声明歌曲播放控制的相关方法,包括:
1) private void play()
2) private void pause()
3) private void previous()
4) private void next()
并声明必要的全局变量,例如:
1) private MediaPlayer player
2) private int currentMusicIndex
3) private int pausePosition
并完全必要的初始化,例如在onCreate()方法初始化player
三、使用自定义的Application保存歌曲数据
1. 自定义类MusicPlayerApplication,继承自Application
2. 注册
3. 声明歌曲数据的List集合,并在onCreate()中,为该集合的数据赋值
4. 声明public List getMusics()方法,返回数据,以便于Activity、Service可以通过该方法获取歌曲数据
四、实现Service中的方法可以被Activity调用
1. 声明新的接口文件IMusicPlayer,并在接口中声明那些由Service实现、由Activity调用的方法,例如void play()等等
2. 使得Service可以被绑定,即声明内部类InnerBinder,继承自Binder,实现IMusicPlayer接口,在onBind()中,创建InnerBinder的对象,作为该方法的返回值
五、实现基本播放控制
1. 实现Activity绑定Service
1) 声明内部类InnerServiceConnection,实现ServiceConnection接口
2) 在Activity的onCreate()中调用bindService()方法实现绑定,其中,方法的第1个参数是Intent对象,用于指定被激活的组件,第2个参数以上第(1)个步骤的内部类对象,且应该被声明为全局变量,第3个参数取值为常量BIND_AUTO_CREATE
3) 声明IMusicPlayer的全局变量player,该变量的值将在InnerServiceConnection的onServiceConnected()方法中,根据第2个参数强制类型转换得到。
2. 实现“播放/暂停”按钮的点击与响应
1) 声明控件
2) 初始化控件
3) 为控件配置监听器
4) 在监听方法中,判断当前播放状态,以决定调用player对象的play()方法或pause()方法,并更新ImageButton上显示的图片
3. 实现播放上一首和下一首,参照以上步骤即可
4. 实现点击列表项播放歌曲
1) 在IMusicPlayer中添加void play(int position)抽象方法
2) 在Service的InnerBinder中实现该方法
3) 在Activity中为ListView配置OnItemClickListener
4) 在监听方法中,直接调用新的play(int position)即可
六、实现播放信息的显示

Application
-----------------------------------
Application是由Android系统进行管理、维护的。每个Android应用程序中必然有且仅有1个Application组件。
Application会在应用程序运行初期被创建,并在所有组件完全退出后被销毁。
由于Application存在的时间最长,所以,可以用于保存“应用程序级别的”全局变量。
自定义Application:
1. 自定义类,继承自Application
2. 在AndroidManifest.xml中,直接在已有的节点配置android:name属性,取值为自定义Application的包名+类名

评论已关闭。