安卓开发-网络及其他高级部分

原视频链接

简要目录

  • 1、测试网络接口-动态权限获取
    • 1.1 网络权限声明
    • 1.2 手机交互权限(文件权限)
    • 1.3 弹出获取/动态获取
      • 1.3.1 获取根目录:
      • 1.3.2 动态获取权限
        • 1.3.2.1 获取权限的方法
        • 1.3.2.2 权限获取回调(activity的回调函数)
  • 2、测试网络接口-Vollery网络调用+gson解析json数据
    • 2.1 Vollery: 调用接口
      • 2.1.1 测试接口: 一言接口
      • 2.1.2 简单调用
      • 2.1.2.1 导入相应的jar及依赖
      • 2.1.3 封装httpUtils
  • 3、Activity、Fragment的生命周期
    • 3.1 Activity生命周期
    • 3.2 Fragment生命周期
  • 4、交互对话框Toast、Dialog、下弹框的使用
    • 1、Toast提示框
    • 2、AlertDialog对话框
      • 2.1 简单使用
      • 2.2 使用自定义dialog模版
      • 2.3 使用第三方插件(BottomSheetDialog)
        • 2.3.1 推荐阅读
        • 2.3.2 导入
        • 2.3.3 简单使用
  • 5、Animation动画、属性动画(上)
    • 5.1 Animation动画(不改变物理像素、效果动画)
      • 5.1.1 帧动画: 连续的播放每一帧的图片
      • 5.1.2 补间动画
      • 5.1.3 缩放动画
      • 5.1.4 旋转动画
      • 5.1.5 透明度动画
    • 5.2 属性动画
      • 5.2.1 方法一:
      • 5.2.2 方法二(也只是动画效果、不修改实际物理位置)
  • 6、Animation动画、属性动画(下)
    • 6.1 技巧动画
      • 6.1.1 listView子级动画
        • 6.1.1.1创建一个子级的组合动画
        • 6.1.1.2 创建一个layoutAnimation父级动画
        • 6.1.1.3 给listView使用
      • 6.1.2 跳转Activit使用动画
      • 6.1.3 共享元素跳转
        • 6.1.3.1 跳转界面
        • 6.1.3.2 设置接受动画的组件
  • 7、Media媒体播放音乐、视频
    • 7.1 音乐
      • 7.1.1 播放本地资源
      • 7.1.2 播放网络资源
      • 7.1.3 设置
    • 7.2 视频
      • 7.2.1 设置资源
      • 7.2.2 播放网络视频
      • 7.2.3 设置
      • 7.2.3 推荐第三方播放插件
  • 8、传感器及隐式跳转
  • 8.1、初始化
    • 8.1.1、初始化
    • 8.1.2、继承接口并实现方法
  • 8.2、获取手机支持的所有传感器
  • 8.3、重力感应
    • 8.3.1 注册传感器
    • 8.3.2 监听判断
  • 8.4、光照感应器(外部对手机的光照)
    • 8.4.1 注册传感器
    • 8.4.2 监听判断
  • 8.5、隐式跳转(跳转系统界面)
    • 8.5.1 跳转电话
    • 8.5.2 跳转短信
    • 8.5.3 跳转相机
  • 9、指纹识别+NFC
    • 9.1 系统指纹识别
      • 9.1.1 初始化
      • 9.1.2 识别代码
      • 9.1.3 最后判断使用
    • 9.2 NFC感应使用
      • 9.2.1 申请权限(动态获取)
      • 9.2.2 准备一个NFC的工具类
      • 9.2.3 初始化
      • 9.2.4 监测是否拥有/开启nfc
      • 9.2.5 优化清空缓存
      • 9.2.5 传感回调
      • 9.2.5 获取数据
  • 10、Service服务+广播的简单使用(理解)
    • 10.1 理解service和广播
    • 10.2 构造
  • 11 、Service服务+广播的简单使用(理解)
    • 11.1 服务(Service)向外互动
      • 11.1.1 发送广播
    • 11.2 页面向服务(Service)交互
      • 11.2.1 Service准备代码
      • 11.2.2 页面绑定服务(Service)并,使用服务的方法
  • 11 、Android中的数据存储/传输(本地数据)
    • 11.1 数据传输
    • 11.2 数据本地存储
      • 11.2.1 使用SharedPreferences实现本地储存
        • 11.2.1.1 初始化
        • 11.2.1.2 使用SharedPreferences
  • 12、Android中的数据存储/传输(Sqlite)
    • 12.1 简单使用SQLiteOpenHelper
    • 12.2 使用Ormlite插件调用sqlite数据库

1、测试网络接口-动态权限获取

1.1 网络权限声明

	
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:usesCleartextTraffic="true">
        <uses-library
            android:name="org.apache.http.legacy"
            android:required="true" />
	application>

1.2 手机交互权限(文件权限)

	
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

1.3 弹出获取/动态获取

1.3.1 获取根目录:

Environment.getExternalStorageDirectory()//--/storage/emulated/0/----这是sd卡的根目录
getFilesDir().getAbsolutePath()//--/data/user/0/com.example.myapplication/files/--这是软件权限目录

1.3.2 动态获取权限

1.3.2.1 获取权限的方法

public static void  getPermissions(Activity activity){
    //判断sdk版本
    if (Build.VERSION.SDK_INT>=23) {
        //获取管理器
        int request= ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
        if (request!= PackageManager.PERMISSION_GRANTED)//如果缺少权限,进行权限申请
        {
            //准备缺少权限的集合,并准备一个回调id
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},20);
            return;//
        }
    }
}

1.3.2.2 权限获取回调(activity的回调函数)

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode){
            case 20:
                if (grantResults.length > 0 && (grantResults[0] == PackageManager.PERMISSION_GRANTED &&
                        grantResults[1] == PackageManager.PERMISSION_GRANTED)) {
                    //同意了
                } else {
                    //拒绝权限,当前界面退出
                    finish();
                }
                break;
        }
    }

2、测试网络接口-Vollery网络调用+gson解析json数据

2.1 Vollery: 调用接口

2.1.1 测试接口: 一言接口

https://v1.hitokoto.cn/

2.1.2 简单调用

2.1.2.1 导入相应的jar及依赖

安卓开发-网络及其他高级部分_第1张图片

	// 解析json
    implementation 'com.google.code.gson:gson:2.8.5'

运行界面

      // 初始化请求队列
        String url = "https://v1.hitokoto.cn/";
        RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
        queue.add(new JsonObjectRequest(Request.Method.GET, url, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject jsonObject) {
                gson = new Gson();
                JsonEntity jsonEntity = gson.fromJson(jsonObject.toString(), JsonEntity.class);
                // Log.d("NETWork", jsonEntity.getHitokoto());
                Message message = new Message();
                message.what = 0x01;
                message.obj = jsonEntity.getHitokoto();
                handler.sendMessage(message);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {

            }
        }));
        // 处理Message 修改主线程UI
        Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what){
                case 0x001:
                    mNetworkTvTest.setText(msg.obj.toString());
            }
        }
    	};

2.1.3 封装httpUtils

public class HttpUtils {
    private static RequestQueue queue;

    public static void get(String path, final Context context, Response.Listener<JSONObject> res) {
        if(queue==null){
            queue  = Volley.newRequestQueue(context);
        }
        queue.add(new JsonObjectRequest(path, res, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                Toast.makeText(context, "访问失败", Toast.LENGTH_SHORT).show();
            }
        }));
    }

    public static void post(String path, final Context context, Response.Listener<JSONObject> res) {
        if(queue==null){
            queue  = Volley.newRequestQueue(context);
        }
        queue.add(new JsonObjectRequest(Request.Method.POST, path, res, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                Toast.makeText(context, "访问失败", Toast.LENGTH_SHORT).show();
            }
        }));
    }
}

调用

		String url = "https://v1.hitokoto.cn/";
        HttpUtils.get(url, getApplicationContext(), new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject jsonObject) {
                // 成功调用的方法
                Log.d("success", jsonObject.toString());
            }
        });

3、Activity、Fragment的生命周期

3.1 Activity生命周期

安卓开发-网络及其他高级部分_第2张图片

  • onCreate: 入口
  • onStart: 渲染
  • onResume: 渲染数据
  • onRestart: 重复渲染界面
  • onPause: 页面显示完成
  • onStop: 隐藏/离开界面
  • onDestory: 销毁界面
@Override
    protected void onStart() {
        super.onStart();
        Log.d(testLog,  "渲染");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(testLog,  "重新渲染");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(testLog,  "渲染数据");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(testLog,  "页面显示完成");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(testLog,  "页面显隐藏");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(testLog,  "销毁");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(testLog, "创建界面");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_net_work_test);
        setView();
        initView();
    }

3.2 Fragment生命周期

安卓开发-网络及其他高级部分_第3张图片

  • 测试生命周期即可
  • setUserVisibleHint: 切换可见监听,加载Fragment为懒加载方式时,不生效
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser){
        //当前页面可见
        Log.d("TestLog","可见");
    }else {
        //滑动并不可见了
        Log.d("TestLog","不可见");
    }
}

4、交互对话框Toast、Dialog、下弹框的使用

1、Toast提示框

简单提示

Toast.makeText(getApplicationContext(), "提示", Toast.LENGTH_SHORT).show();

安卓开发-网络及其他高级部分_第4张图片

2、AlertDialog对话框

2.1 简单使用

				new AlertDialog.Builder(ViewPageTest.this)
                .setTitle("标题")
                .setMessage("内容")
                .setIcon(R.mipmap.ic_launcher)
                .setCancelable(false)
                .setNegativeButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                    }
                })
                .setPositiveButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        
                    }
                })
                .show();

2.2 使用自定义dialog模版

		View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.activity_button_test, null);
        // 获取dialog内部的button并监听其点击效果
        Button button =  view.findViewById(R.id.button_bt_test);
        // 如果是在Activity的话,上下文必须用当前的上下文才可以
        // 如果是在Fragment的话,则可以用getApplicationContext()
        AlertDialog dialog = new AlertDialog.Builder(ViewPageTest.this)
                .setView(view)
                .show();
        // 设置点击按钮后的取消操作
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog.cancel();
            }
        });

2.3 使用第三方插件(BottomSheetDialog)

2.3.1 推荐阅读

https://www.jianshu.com/p/859943121b05

2.3.2 导入

implementation 'com.github.rey5137:material:1.2.5'

2.3.3 简单使用

  View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.activity_button_test, null);
   // 如果是在Activity的话,上下文必须用当前的上下文才可以
   // 如果是在Fragment的话,则可以用getApplicationContext()
  final BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(ButtonTest.this);
        bottomSheetDialog
                .contentView(view)
                .inDuration(800)
                .outDuration(800)
                .cancelable(true)
                .show;

5、Animation动画、属性动画(上)

5.1 Animation动画(不改变物理像素、效果动画)

5.1.1 帧动画: 连续的播放每一帧的图片

  • 准备图片资源
  • 准备帧动画资源: 在drawable文件中创建即可
    安卓开发-网络及其他高级部分_第5张图片
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:duration="100"
        android:drawable="@drawable/listimage01">
    item><item android:duration="100"
        android:drawable="@drawable/listimage02">
    item><item android:duration="100"
        android:drawable="@drawable/listimage03">
    item><item android:duration="100"
        android:drawable="@drawable/listimage04">
    item>
animation-list>
  • 给图片作为背景
   <ImageView
        android:id="@+id/anm_iv_test"
        android:background="@drawable/anm_test01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
  • 获取背景并播放
public class AnimationTest extends AppCompatActivity {

    private ImageView mAnmIvTest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation_test);
        initView();
        setView();
    }

    private void setView() {
        AnimationDrawable animationDrawable = (AnimationDrawable)mAnmIvTest.getBackground();
        animationDrawable.start();
    }

    private void initView() {
        mAnmIvTest = (ImageView) findViewById(R.id.anm_iv_test);
    }
}

5.1.2 补间动画

  • 创建动画文件包:anim
    安卓开发-网络及其他高级部分_第6张图片安卓开发-网络及其他高级部分_第7张图片
  • 准备动画资源文件(注意名字不能大写)
    • 使用动画
    • translate:平移动画
    • fromXDelta:起始X轴位置
    • fromYDelta:起始Y轴位置
      • toXDelta:到X的位置
      • toYDelta:到Y的位置
      • duration:中间动画的时间(注意这个不提示,需要手写)
      • 注意:这里通常使用%计算单位,面向与父容器的宽高
<translate 
    android:fromXDelta="0%" 
    android:fromYDelta="0%" 
    android:toXDelta="50%" 
    android:toYDelta="0%"
    android:duration="1000" 
    xmlns:android="http://schemas.android.com/apk/res/android" >

translate>
  • 使用
        Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_translate);
        mAnmIvTest.startAnimation(animation);

5.1.3 缩放动画

  • fromXScale:初始X大小
  • toXScale:缩小后的X大小
  • pivotX、pivotY:X、Y的中心点
<scale
    android:fromXScale="0%"
    android:fromYScale="0%"
    android:toXScale="80%"
    android:toYScale="80%"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="1000"
    xmlns:android="http://schemas.android.com/apk/res/android">
scale>
    private void setView() {
        Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_scale);
        mAnmIvTest.startAnimation(animation);
    }

    private void initView() {
        mAnmIvTest = (ImageView) findViewById(R.id.anm_iv_test);
    }

5.1.4 旋转动画

  • fromDegrees:初始角度
  • toDegrees:旋转后角度
    • pivotX、pivotY:X、Y的中心点

<rotate
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="1000"
    xmlns:android="http://schemas.android.com/apk/res/android">
rotate>
    private void setView() {
        Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_rotate);
        mAnmIvTest.startAnimation(animation);
    }

    private void initView() {
        mAnmIvTest = (ImageView) findViewById(R.id.anm_iv_test);
    }

5.1.5 透明度动画

  • fromAlpha:初始透明度
  • toAlpha:最后透明度

注意:这里范围是:0.0-1.0


<alpha
    android:fromAlpha="0.2"
    android:toAlpha="1"
    android:duration="1000"
    xmlns:android="http://schemas.android.com/apk/res/android">
alpha>
    private void setView() {
        Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_alpha);
        mAnmIvTest.startAnimation(animation);
    }

    private void initView() {
        mAnmIvTest = (ImageView) findViewById(R.id.anm_iv_test);
    }

5.2 属性动画

5.2.1 方法一:

  • 属性动画简述:
    • 以动画的形式改变像素位置
    • 动画结束后组件固定位置
  • 简单使用:
    • 通过ValueAnimator获取动态值
    • 通过动态值,改变组件的物理高度
    • 注意:这里的单位是一致的
  		mAnmIvTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ValueAnimator animator = ValueAnimator.ofInt(0,330);
                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
                        //获取当前的height值
                        //动态更新view的高度
                        mAnmIvTest.getLayoutParams().height = (int) (Integer)animator.getAnimatedValue();
                        mAnmIvTest.requestLayout();
                    }
                });
                animator.setDuration(1000);
                animator.start();
            }
        });

5.2.2 方法二(也只是动画效果、不修改实际物理位置)

 		// 组件、动画效果(translateX....)、1f->2f 从初始放大两倍
        ObjectAnimator animatorX = ObjectAnimator.ofFloat(mAnmIvTest, "scaleX", 1f, 2f);
        ObjectAnimator animatorY = ObjectAnimator.ofFloat(mAnmIvTest, "scaleY", 1f, 2f);
        animatorX.setDuration(1000);
        animatorY.setDuration(1000);
        animatorX.start();
        animatorY.start();

6、Animation动画、属性动画(下)

6.1 技巧动画

6.1.1 listView子级动画

6.1.1.1创建一个子级的组合动画


<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="10%"
        android:toXDelta="0%"
        android:duration="500"/>
    <alpha
        android:fromAlpha="0.6"
        android:toAlpha="1"
        android:duration="500"/>
set>

6.1.1.2 创建一个layoutAnimation父级动画

  • delay: 延时时间(秒)
  • animationOrder:子级显示模式
    • normal:按顺序
    • reverse:倒序
    • random:随机
    • delay:每个子级间隔
    • animation:子集动画


<layoutAnimation
    android:animationOrder="normal"
    android:delay="0.5" 
    android:animation="@anim/anim_list_item_set"
    xmlns:android="http://schemas.android.com/apk/res/android">

layoutAnimation>

6.1.1.3 给listView使用

安卓开发-网络及其他高级部分_第8张图片

 <ListView
        android:layoutAnimation="@anim/anim_list_set"/>

6.1.2 跳转Activit使用动画

  • 普通跳转
// 普通跳转
Intent intent = new Intent();
intent.setClass(getApplicationContext(), ButtonTest.class);
startActivity(intent);
  • 普通模板跳转页面
    anin_in.xml

<alpha
    android:fromAlpha="1"
    android:toAlpha="0"
    android:duration="1000"
    xmlns:android="http://schemas.android.com/apk/res/android">

alpha>

anin_out.xml


<alpha
    android:fromAlpha="1"
    android:toAlpha="0"
    android:duration="1000"
    xmlns:android="http://schemas.android.com/apk/res/android">

alpha>
Intent intent = new Intent();
intent.setClass(getApplicationContext(), ButtonTest.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(AnimationTest.this).toBundle());
overridePendingTransition(R.anim.anim_in,R.anim.anim_out);

注意:
overridePendingTransition方法一定在startActivity后面
overridePendingTransition:参数1:当前页面消失动画,参数2:下个页面进入动画

设置接收动画(跳转到哪个界面则在那个界面中设置接受)

 getWindow().setEnterTransition(new Explode());//需要接收动画

在跳转的界面接收即可

6.1.3 共享元素跳转

6.1.3.1 跳转界面

Intent intent = new Intent();
intent.setClass(getApplicationContext(), ButtonTest.class);
startActivity(intent,ActivityOptions.makeSceneTransitionAnimation(
// create后面的参数为(哪个组件接受、"共享的参数名")
AnimationTest.this, Pair.<View, String>create(mAnmIvTest,"iv_bt")).toBundle());
  • 同样使用ActivityOptions
  • Pair:添加共享元素的集合即可:一个组件和一个共享名
  • 最后.toBundel()

6.1.3.2 设置接受动画的组件

接受的组件的共享名
安卓开发-网络及其他高级部分_第9张图片

7、Media媒体播放音乐、视频

7.1 音乐

7.1.1 播放本地资源

  • 软件资源
MediaPlayer.create(AnimationTest.this, R.raw.test);
  • sd资源
try {
    mediaPlayer.setDataSource("../music/samsara.mp3") ;
} catch (IOException e) {
    e.printStackTrace();
}

7.1.2 播放网络资源

mMediaPlayer.setDataSource("http://..../xxx.mp3") ;
  • 使用异步: prepareAsync\
  • 并缓存完成才能播放:setOnPreparedListener

7.1.3 设置

  • 需使用异步缓冲
 mMediaPlayer.prepareAsync();
  • 缓存完成后
 setOnPreparedListener
  • 监听缓存进度
setOnBufferingUpdateListener
  • 播放完成后
setOnCompletionListener
  • 获取当前进度
mediaPlayer.getCurrentPosition();
  • 获取总播放进度:帧
mediaPlayer.getDuration()
  • 设置进度
mediaPlayer.seekTo()
  • 暂停
 mediaPlayer.pause();
  • 继续/播放
 mediaPlayer.start();
  • 停止
 mediaPlayer.stop();
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".activitys.MediaTest">

    <SeekBar
        android:id="@+id/media_sb_test"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

LinearLayout>
public class MediaTest extends AppCompatActivity {

    private SeekBar mediaSbTest;

    private MediaPlayer mediaPlayer;

    Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            mediaSbTest.setProgress(mediaPlayer.getCurrentPosition());
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_media_test);
        initView();
        setView();
    }

    private void setView() {
        // 设置本地资源
        // mediaPlayer = MediaPlayer.create(MediaTest.this, R.raw.test_01);
        // 设置网络资源(如果设置了网络资源,则必须要设置为异步加载)
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource("http://downsc.chinaz.net/files/download/sound1/201206/1638.mp3");
            // 异步缓存
            mediaPlayer.prepareAsync();
            // 监听是否缓存完成
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mediaPlayer) {
                    mediaPlayer.start();
                    int duration = mediaPlayer.getDuration();
                    mediaSbTest.setMax(duration);
                }
            });

            // 监听缓存进度
            mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
                @Override
                public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {
                }
            });
            new Thread() {
                @Override
                public void run() {
                    while ( mediaPlayer.getCurrentPosition() <= mediaPlayer.getDuration()) {
                        try {
                            // 监听播放缓存进度
                            Message message = new Message();
                            handler.sendMessage(message);
                            sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                }
            }.start();

            mediaSbTest.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                    int progress = seekBar.getProgress();
                    mediaPlayer.seekTo(progress);
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {

                }

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {

                }
            });
        }catch (IOException e) {

        }

    }

    private void initView() {
        mediaSbTest = (SeekBar) findViewById(R.id.media_sb_test);
    }
}

7.2 视频

7.2.1 设置资源

  • sd资源
setVideoURI(Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.test_mp4));
  • 静态资源
setVideoPath("android.resource://"+getPackageName()+"/"+R.raw.test_mp4);

7.2.2 播放网络视频

videoView.setVideoPath("https:/...");

缓存完成才能播放:setOnPreparedListener

7.2.3 设置

  • 绑定进度条
//设置进度条
MediaController mc = new MediaController(AnimationTest.this);  //注意上下文
videoView.setMediaController(mc);
  • 缓存完成
setOnPreparedListener
  • 播放结束
setOnCompletionListener
  • 设置进度
seekTo

7.2.3 推荐第三方播放插件

  • 哔哩哔哩开源:ijkplayer
    <VideoView
        android:id="@+id/media_vv_test"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
		 /**
         * 播放视频
         */
        mediaVvTest.setVideoPath("android.resource://"+getPackageName()+"/"+R.raw.test_02);
        mediaVvTest.start();
        // 增加控制器并且绑定
        MediaController  mediaController = new MediaController(MediaTest.this);
        mediaVvTest.setMediaController(mediaController);

8、传感器及隐式跳转

传感器

8.1、初始化

8.1.1、初始化

SensorManager mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);//获取传感器管理器
//创建一个SensorManager来获取系统的传感器服务
SensorManager  sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

8.1.2、继承接口并实现方法

implements SensorEventListener{}

  @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        //监听回调
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }

8.2、获取手机支持的所有传感器

List<Sensor> sensorList;
// 实例化传感器管理者

// 得到设置支持的所有传感器的List
sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
for (Sensor sensor : sensorList) {
    Log.d("FDFDS", "onResume: " + sensor.getName());
}

8.3、重力感应

8.3.1 注册传感器

//注册传感器
 sm.registerListener((SensorEventListener) this, sm.getDefaultSensor(Sensor.TYPE_GRAVITY), SensorManager.SENSOR_DELAY_NORMAL);

8.3.2 监听判断

if(sensorEvent.sensor.getType() == Sensor.TYPE_GRAVITY) {
    float X = sensorEvent.values[0];
    float Y = sensorEvent.values[1];
    float Z = sensorEvent.values[2];
    Log.d("FDFDS","x方向的重力加速度\n" + X);
    Log.d("FDFDS","Y方向的重力加速度\n" + Y);
    Log.d("FDFDS","Z方向的重力加速度\n" + Z);
}

8.4、光照感应器(外部对手机的光照)

8.4.1 注册传感器

//注册传感器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_LIGHT), SensorManager.SENSOR_DELAY_NORMAL);

8.4.2 监听判断

if(sensorEvent.sensor.getType() == Sensor.TYPE_LIGHT){
    float X = sensorEvent.values[0];
    Log.d("FDFDS","光强度为为"+ X );
}

8.5、隐式跳转(跳转系统界面)

8.5.1 跳转电话

Intent Intent =  new Intent(android.content.Intent.ACTION_DIAL, Uri.parse("tel:" + "123123123"));//跳转到拨号界面,同时传递电话号码
startActivity(Intent);

8.5.2 跳转短信

//指定联系人
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:我是指定联系人"));
intent.putExtra("sms_body", "内容");
startActivity(intent);

8.5.3 跳转相机

  • 申请权限
<!--拍照-->
<uses-permission android:name="android.permission.CAMERA" />```
- 动态获取权限
- 隐式跳转
```java
//跳转相机
private void toCamera() {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);  //跳转到 ACTION_IMAGE_CAPTURE
    //判断内存卡是否可用,可用的话就进行存储
    //putExtra:取值,Uri.fromFile:传一个拍照所得到的文件,fileImg.jpg:文件名
    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory(),"fileImg.jpg")));
    startActivityForResult(intent,101); // 101: 相机的返回码参数(随便一个值就行,只要不冲突就好)
}
  • 6.0以上版本闪退问题(调用摄像头时应该进行这步操作)
//跳转相机动态权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
    StrictMode.setVmPolicy(builder.build());
}

9、指纹识别+NFC

9.1 系统指纹识别

推荐阅读

9.1.1 初始化

FingerprintManager manager;
KeyguardManager mKeyManager;
private final static int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 0;
private final static String TAG = "finger_log";
manager = (FingerprintManager) this.getSystemService(Context.FINGERPRINT_SERVICE);
mKeyManager = (KeyguardManager) this.getSystemService(Context.KEYGUARD_SERVICE);

9.1.2 识别代码

@RequiresApi(api = Build.VERSION_CODES.M)
public boolean isFinger() {

    //android studio 上,没有这个会报错 
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
        Toast.makeText(this, "没有指纹识别权限", Toast.LENGTH_SHORT).show();
        return false;
    }
    Log(TAG, "有指纹权限");
    //判断硬件是否支持指纹识别 
    if (!manager.isHardwareDetected()) {
        Toast.makeText(this, "没有指纹识别模块", Toast.LENGTH_SHORT).show();
        return false;
    }
    Log(TAG, "有指纹模块");
    //判断 是否开启锁屏密码 

    if (!mKeyManager.isKeyguardSecure()) {
        Toast.makeText(this, "没有开启锁屏密码", Toast.LENGTH_SHORT).show();
        return false;
    }
    Log(TAG, "已开启锁屏密码");
    //判断是否有指纹录入 
    if (!manager.hasEnrolledFingerprints()) {
        Toast.makeText(this, "没有录入指纹", Toast.LENGTH_SHORT).show();
        return false;
    }
    Log(TAG, "已录入指纹");

    return true;
}

CancellationSignal mCancellationSignal = new CancellationSignal();
//回调方法 
FingerprintManager.AuthenticationCallback mSelfCancelled = new FingerprintManager.AuthenticationCallback() {
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onAuthenticationError(int errorCode, CharSequence errString) {
        //但多次指纹密码验证错误后,进入此方法;并且,不能短时间内调用指纹验证 
        Toast.makeText(MediaTest.this, errString, Toast.LENGTH_SHORT).show();
        showAuthenticationScreen();
    }

    @Override
    public void onAuthenticationHelp(int helpCode, CharSequence helpString) {

        Toast.makeText(MediaTest.this, helpString, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {

        Toast.makeText(MediaTest.this, "指纹识别成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onAuthenticationFailed() {
        Toast.makeText(MediaTest.this, "指纹识别失败", Toast.LENGTH_SHORT).show();
    }
};


@RequiresApi(api = Build.VERSION_CODES.M)
public void startListening(FingerprintManager.CryptoObject cryptoObject) {
    //android studio 上,没有这个会报错 
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
        Toast.makeText(this, "没有指纹识别权限", Toast.LENGTH_SHORT).show();
        return;
    }
    manager.authenticate(cryptoObject, mCancellationSignal, 0, mSelfCancelled, null);


}

/**
     * 锁屏密码 
     */
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void showAuthenticationScreen() {

    Intent intent = mKeyManager.createConfirmDeviceCredentialIntent("finger", "测试指纹识别");
    if (intent != null) {
        startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
        // Challenge completed, proceed with using cipher 
        if (resultCode == RESULT_OK) {
            Toast.makeText(this, "识别成功", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "识别失败", Toast.LENGTH_SHORT).show();
        }
    }
}

private void Log(String tag, String msg) {
    Log.d(tag, msg);
}

9.1.3 最后判断使用

if (isFinger()) {
    Toast.makeText(MediaTest.this, "请进行指纹识别", Toast.LENGTH_LONG).show();
    startListening(null);
}

9.2 NFC感应使用

9.2.1 申请权限(动态获取)

<uses-feature
              android:name="android.hardware.nfc"
              android:required="true" />
<uses-permission android:name="android.permission.NFC" />

9.2.2 准备一个NFC的工具类

public class NfcUtils {
    //nfc
    public  NfcAdapter mNfcAdapter;
    public static IntentFilter[] mIntentFilter = null;
    public static PendingIntent mPendingIntent = null;
    public static String[][] mTechList = null;

    public NfcUtils(Activity activity) {
        mNfcAdapter = NfcCheck(activity);
        NfcInit(activity);
    }

    /**
     * 检查NFC是否打开
     */
    public static NfcAdapter NfcCheck(Activity activity) {
        NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(activity);
        if (mNfcAdapter == null) {
            Toast.makeText(activity, "设备不支持NFC功能!", Toast.LENGTH_SHORT).show();
            return null;
        } else {
            if (!mNfcAdapter.isEnabled()) {
                IsToSet(activity);
            } else {
                Toast.makeText(activity, "NFC功能已打开!", Toast.LENGTH_SHORT).show();
            }
        }
        return mNfcAdapter;
    }

    /**
     * 初始化nfc设置
     */
    public static void NfcInit(Activity activity) {
        Intent intent = new Intent(activity, activity.getClass());
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        mPendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
        //做一个IntentFilter过滤你想要的action 这里过滤的是ndef
        IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        //如果你对action的定义有更高的要求,比如data的要求,你可以使用如下的代码来定义intentFilter
        //        IntentFilter filter2 = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        //        try {
        //            filter.addDataType("*/*");
        //        } catch (IntentFilter.MalformedMimeTypeException e) {
        //            e.printStackTrace();
        //        }
        //        mIntentFilter = new IntentFilter[]{filter, filter2};
        //        mTechList = null;
        try {
            filter.addDataType("*/*");
        } catch (IntentFilter.MalformedMimeTypeException e) {
            e.printStackTrace();
        }
        mTechList = new String[][]{{MifareClassic.class.getName()},
                {NfcA.class.getName()}};
        //生成intentFilter
        mIntentFilter = new IntentFilter[]{filter};
    }


    /**
     * 读取NFC的数据
     */
    public static String readNFCFromTag(Intent intent) throws UnsupportedEncodingException {
        Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (rawArray != null) {
            NdefMessage mNdefMsg = (NdefMessage) rawArray[0];
            NdefRecord mNdefRecord = mNdefMsg.getRecords()[0];
            if (mNdefRecord != null) {
                String readResult = new String(mNdefRecord.getPayload(), "UTF-8");
                return readResult;
            }
        }
        return "";
    }


    /**
     * 往nfc写入数据
     */
    public static void writeNFCToTag(String data, Intent intent) throws IOException, FormatException {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        Ndef ndef = Ndef.get(tag);
        ndef.connect();
        NdefRecord ndefRecord = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            ndefRecord = NdefRecord.createTextRecord(null, data);
        }
        NdefRecord[] records = {ndefRecord};
        NdefMessage ndefMessage = new NdefMessage(records);
        ndef.writeNdefMessage(ndefMessage);
    }

    /**
     * 读取nfcID
     */
    public static String readNFCId(Intent intent) throws UnsupportedEncodingException {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        String id = ByteArrayToHexString(tag.getId());
        return id;
    }

    /**
     * 将字节数组转换为字符串
     */
    private static String ByteArrayToHexString(byte[] inarray) {
        int i, j, in;
        String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
        String out = "";

        for (j = 0; j < inarray.length; ++j) {
            in = (int) inarray[j] & 0xff;
            i = (in >> 4) & 0x0f;
            out += hex[i];
            i = in & 0x0f;
            out += hex[i];
        }
        return out;
    }

    private static void IsToSet(final Activity activity) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("是否跳转到设置页面打开NFC功能");
//        builder.setTitle("提示");
        builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                goToSet(activity);
                dialog.dismiss();
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.create().show();
    }

    private static void goToSet(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BASE) {
            // 进入设置系统应用权限界面
            Intent intent = new Intent(Settings.ACTION_SETTINGS);
            activity.startActivity(intent);
            return;
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {// 运行系统在5.x环境使用
            // 进入设置系统应用权限界面
            Intent intent = new Intent(Settings.ACTION_SETTINGS);
            activity.startActivity(intent);
            return;
        }
    }
}

9.2.3 初始化

 NfcUtils  nfcUtils = new NfcUtils(this);

9.2.4 监测是否拥有/开启nfc

//设定intentfilter和tech-list。如果两个都为null就代表优先接收任何形式的TAG action。也就是说系统会主动发TAG intent。
if (nfcUtils.mNfcAdapter != null) {
    nfcUtils.mNfcAdapter.enableForegroundDispatch(this, NfcUtils.mPendingIntent, NfcUtils.mIntentFilter, NfcUtils.mTechList);
}else {
    Toast.makeText(this, "调用失败", Toast.LENGTH_SHORT).show();
}

一般在生命周期的onResume(渲染数据)方法中判断

9.2.5 优化清空缓存

@Override
protected void onDestroy() {
    super.onDestroy();
    nfcUtils.mNfcAdapter = null;
}
@Override
protected void onPause() {
    super.onPause();
    if (nfcUtils.mNfcAdapter != null) {
        nfcUtils.mNfcAdapter.disableForegroundDispatch(this);
    }
}

9.2.5 传感回调

//在onNewIntent中处理由NFC设备传递过来的intent
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    Log.e(TAG, "--------------NFC-------------" );
    processIntent(intent);
}

9.2.5 获取数据

//  这块的processIntent() 就是处理卡中数据的方法
public void processIntent(Intent intent) {
    Parcelable[] rawmsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);//获取数据
    Toast.makeText(this, "读取成功!", Toast.LENGTH_SHORT).show();
}

10、Service服务+广播的简单使用(理解)

10.1 理解service和广播

  • 四大组件之一
    • activity(活动/界面)
    • service(服务)
    • Broadcast Receive(广播)
    • Content Provider(内容提供者)
  • 可以比作为线程的逻辑
  • 服务: 服务于全软件界面,生命周期在全软件当中,可以通过广播与全局的界面交互
  • 广播发送全软件界面

10.2 构造

安卓开发-网络及其他高级部分_第10张图片

public class MyService extends Service {

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(BasDataUtil.LOG_TOAST, "服务销毁;");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(BasDataUtil.LOG_TOAST, "服务创建----Create");
    }

    public MyService() {
        Log.d(BasDataUtil.LOG_TOAST, "实例化MyService服务");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(BasDataUtil.LOG_TOAST, "服务----绑定成功");
        // TODO: Return the communication channel to the service.
        //返回到服务的通信通道。
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            String activityKey = intent.getStringExtra("data");
            if (activityKey!=null){
             //intent传入的参数接收
            }
        }catch (Exception e){
            Log.d(BasDataUtil.LOG_TOAST,"播放音乐服务--发广播/收广播错误:"+e.toString());
        }

        return super.onStartCommand(intent, flags, startId);
    }
    
    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(BasDataUtil.LOG_TOAST, "解绑MyService成功");
        return super.onUnbind(intent);
    }
}

注意:
启动服务调用的是onCreate
关闭服务调用的是:onDestroy
绑定服务调用的是onBind
取消绑定调用的是:onUnbind
intent传参数 跳转 服务,需要接收使用:onStartCommand,与服务进行绑定

Intent intent = new Intent(this, MyService.class);  
startService(intent);

11 、Service服务+广播的简单使用(理解)

11.1 服务(Service)向外互动

11.1.1 发送广播

  • 服务准备代码
private LocalBroadcastManager localBroadcastManager;	//准备发送广播控制器
@Override
public void onCreate() {
    localBroadcastManager = LocalBroadcastManager.getInstance(this);	//实例化
    super.onCreate();
    Log.d(BasDataUtil.LOG_TOAST, "服务----Create");
}
//--------发送广播
Intent intent = new Intent("com.example.Service");	//准备一个intent:并实例一个标识:可使用自己的包名
intent.putExtra("dataKey", "dataKey的值");//需要传入的参数
localBroadcastManager.sendBroadcast(intent);	//使用广播发送器发送
  • 接收广播
private LocalReceiver localReceiver;
private IntentFilter intentFilter;
///--提供广播监听
//监听广播
class LocalReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        try {
            String dataKey = intent.getStringExtra("dataKey");
            //判定获取是否成功
        }catch (Exception e){
            Log.d(BasDataUtil.LOG_TOAST,"播放接收广播错误:"+e.toString());
        }

    }
}
//--在该页注册广播
@Override
protected void onStart() {
    //注册本地广播监听器
    intentFilter = new IntentFilter();	//实例
    intentFilter.addAction("com.example.Service");//绑定标识
    localReceiver = new LocalReceiver();	//实例
    //广播
    LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(PlayListActivity.this);//通过getInstance()得到LocalBroadcastManager的实例;
    localBroadcastManager.registerReceiver(localReceiver, intentFilter);//启动广播接收
    super.onStart();
}

11.2 页面向服务(Service)交互

11.2.1 Service准备代码

//准备一个给页面调用的类
class PlayMusicBinder extends Binder {//例如这里可以直接播放,暂停,继续...各种操作

    public PlayMusicBinder() {
        //初始化控制器
        mediaPlayer = new MediaPlayer();

    }
	public String  getData(){
        return "这是服务中的方法";
    }

}
//准备一个IBinder,与页面交互:绑定立马调用
@Override
public IBinder onBind(Intent intent) {
    Log.d(BasDataUtil.LOG_TOAST, "服务----绑定成功");
    // TODO: Return the communication channel to the service.
    return new PlayMusicBinder();	//返回服务中的Binder类
}

11.2.2 页面绑定服务(Service)并,使用服务的方法

PlayMusicBinder playMusicBinder;
//--准备一个接收服务管理器:绑定后直接调用
private ServiceConnection connection = new ServiceConnection() {
    /**
         * 连接到服务
         * @param name
         * @param service
         */
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        //连接服务成功
        playMusicBinder = (PlayMusicBinder) service;//这里就直接获取了playMusicBinder控制
    }

    /**
         * 断开连接
         * @param name
         */
    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
};
//--绑定服务
@Override
protected void onStart() {
    //        绑定服务
    bindService(new Intent(getApplicationContext(), AudioService.class), connection, Service.BIND_AUTO_CREATE);
    super.onStart();
}
//---这个时候就可以直接使用了
playMusicBinder.getData();

全部代码
服务端代码
MyService.java

public class MyService extends Service {

    MediaPlayer mediaPlayer;

    String musicSrc = "暂无";

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(BaseData.LOG_TOAST, "服务销毁;");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(BaseData.LOG_TOAST, "服务创建----Create");
    }

    public MyService() {
        Log.d(BaseData.LOG_TOAST, "实例化MyService服务");
    }


    /**
     * 绑定
     * @param intent
     * @return
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(BaseData.LOG_TOAST, "服务----绑定成功");
        // TODO: Return the communication channel to the service.
        //返回到服务的通信通道。
        return new PlayMusicBinder();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            String activityKey = intent.getStringExtra("data");
            if (activityKey!=null){
                //intent传入的参数接收
            }
        }catch (Exception e){
            Log.d(BaseData.LOG_TOAST,"播放音乐服务--发广播/收广播错误:"+e.toString());
        }

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(BaseData.LOG_TOAST, "解绑MyService成功");
        return super.onUnbind(intent);
    }

    class PlayMusicBinder extends Binder{
        public PlayMusicBinder() {
            mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.test_01);
        }

        public void initMusic(String src){
            musicSrc = src;
        }

        public void playMusic(){
            if(mediaPlayer != null){
                mediaPlayer.start();
            }
        }

        public void stopMusic(){
            if(mediaPlayer != null){
                mediaPlayer.stop();
            }
        }

        public void test(){
            Log.d(BaseData.LOG_TOAST,"调用了服务的方法");
            // 可以直接写入播放音乐的相关代码
        }
    }

界面交互代码

public class ServiceTest extends AppCompatActivity implements View.OnClickListener {

    MyService.PlayMusicBinder playMusicBinder;
    private Button mServiceBtInit;
    private Button mServiceBtPlay;
    private Button mServiceBtStop;

    @Override
    protected void onStart() {
        super.onStart();
        // 绑定服务
        bindService(new Intent(getApplicationContext(), MyService.class), connection, Service.BIND_AUTO_CREATE);
    }

    /**
     * 创建服务链接器
     */
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // 链接成功
            playMusicBinder = (MyService.PlayMusicBinder) iBinder;

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service_test);
        setView();
        initView();
    }

    private void setView() {
//        startActivity(new Intent(getApplicationContext(), ServiceTest2.class));

    }


    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.service_bt_init:
                Toast.makeText(ServiceTest.this, "初始化", Toast.LENGTH_SHORT).show();
                playMusicBinder.initMusic("sss");
                break;
            case R.id.service_bt_play:
                Toast.makeText(ServiceTest.this, "开始", Toast.LENGTH_SHORT).show();
                playMusicBinder.playMusic();
                break;
            case R.id.service_bt_stop:
                Toast.makeText(ServiceTest.this, "停止", Toast.LENGTH_SHORT).show();
                playMusicBinder.stopMusic();
                break;
        }

    }

    private void initView() {
        mServiceBtInit = (Button) findViewById(R.id.service_bt_init);
        mServiceBtPlay = (Button) findViewById(R.id.service_bt_play);
        mServiceBtStop = (Button) findViewById(R.id.service_bt_stop);
        mServiceBtInit.setOnClickListener(this);
        mServiceBtPlay.setOnClickListener(this);
        mServiceBtStop.setOnClickListener(this);
    }
}

11 、Android中的数据存储/传输(本地数据)

11.1 数据传输

  • 变量
int i;
String s;

使用范围:当前代码块

  • 全局变量
public static int i;
public static String s;

使用范围:跨类可以使用

  • 跳转界面传入数据
    • 传入基础数据

      • 跳转传入数据
        Intent intent =new Intent(getApplicationContext(), Activity2.class);
        intent.putExtra(“key01”,“value01”);
        startActivity(intent);

      • 接受传入的数据
        Intent intent= getIntent();
        Log.d(BaseData.LOG_TOAST,intent.getStringExtra(“key01”));

      这里注意获取可能为null

    • 传入对象

      • 准备一个对象类
        public class User implements Serializable {
        String name;
        int id;

      该类需要继承 implements Serializable ,才能被存入

      • 跳转传入数据
        Intent intent =new Intent(getApplicationContext(), ServiceTset2.class);
        User user = new User(“12”,1);
        Bundle bundle = new Bundle();
        bundle.putSerializable(“user”, user);
        intent.putExtras(bundle);
        startActivity(intent);

      注意:
      这里使用Bundle来存入数据,使用方法和intent类似
      它相当于一个集合

      • 接受传入的数据
        Bundle intent= getIntent().getExtras();
        User user= (User) intent.get(“user”);
        Log.d(BaseData.LOG_TOAST,user.toString());

      使用Bundle设置就得使用Bundle接受

11.2 数据本地存储

11.2.1 使用SharedPreferences实现本地储存

使用范围:全软件,并与软件共存(因为它存在软件里的文件夹里(data/data/shared_perfs/文件名.xml))

11.2.1.1 初始化

SharedPreferences sharedPreferences = getSharedPreferences("testSp",MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
  • testSp:文件名.xml
  • 模式
    • MODE_PRIVATE:默认模式,创建的文件只能由 调用的应用程序(或者共享相同用户ID的应用程序)访问。
  • sharedPreferences:用来读取文件中的键值
  • editor:用于写入文件中的键值

11.2.1.2 使用SharedPreferences

它的数据会一直保存只能自己删除或卸载软件

  • 存入/更新
editor.putString("key","testKey");
editor.apply();
  • 获取
// 指明为哪个本地文件
SharedPreferences sharedPreferences = getSharedPreferences("testSp",MODE_PRIVATE);
sharedPreferences.getString("keyName","默认值");
  • 删除
editor.remove("key");//根据键删除
editor.clear();//清空

12、Android中的数据存储/传输(Sqlite)

12.1 简单使用SQLiteOpenHelper

  • 首先准备一个Helpter的实例类(创建的数据库文件:data/data/软件软件/databases/数据库名.db)
public class SqlitHelper extends SQLiteOpenHelper {
    private static  String SQL_NAME = "testSql.db";
    private static int  SQL_VERSION = 1;
    public SqlitHelper(@Nullable Context context) {
        super(context, SQL_NAME, null, SQL_VERSION);
    }

    //注意这个方法只执行一次,所以在这创建表格
    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "create table tb_user(name varchar(20),pwd varchar(20))";
        db.execSQL(sql);
    }
    //注意这个是数据库更新才调用
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

注意:
这个可以当成模板,不需要死记
onCreate:注意这个方法只执行一次,所以在这创建表格

  • 数据库的查删修
  • 插入
SqlitHelper sqlitHelper = new SqlitHelper(this);
SQLiteDatabase db = sqlitHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name","张三");
values.put("pwd","123");
db.insert("tb_user",null,values);
  • 查询
SqlitHelper sqlitHelper = new SqlitHelper(this);
SQLiteDatabase db = sqlitHelper.getWritableDatabase();
//创建游标对象
Cursor cursor = db.query("tb_user", new String[]{"name","pwd"}, null, null, null, null, null);
//利用游标遍历所有数据对象
while(cursor.moveToNext()){
    String name = cursor.getString(cursor.getColumnIndex("name"));
    String pwd = cursor.getString(cursor.getColumnIndex("pwd"));
    Log.d(BaseData.LOG_TOAST,"数据库:"+name+","+pwd);
}
  • 删除 db.delete()…

12.2 使用Ormlite插件调用sqlite数据库

  • 减少了sql语句操作
  • 增加了对类的面向对象
  • 简单使用
    • 准备一个数据库的实体类
	@DatabaseTable(tableName = "tb_user2")//创建表名
public class UserEntity implements Serializable {
    @DatabaseField()
    String name;
    @DatabaseField()
    String pwd;
    @DatabaseField()
    String age;

注意:

  • DatabaseTable:注释写法,说明这个类对应表格名
  • DatabaseField:这个属性就是一个键
  • 其他写法
@ DatabaseField注解可以有以下字段:
columnName 列名,未指定时为字段名
dataType DataType类的类型的字段。通常的类型是从Java类的领域,并不需要指定。
defaultValue 默认值
width 宽度 默认是0,表示不限
canBeNull 是否允许为空,默认为true
id 主键 默认为false
generatedId 自增长的主键 默认值是false
generatedIdSequence 字符串名称的序列号 类同generatedId,但您可以指定序列的名称使用。默认为null
foreign 外键,默认为false,字段不能是一个原始类型。在外键对象的类中,必须要有一个ID字段(ID, generatedId,generatedIdSequence)
useGetSet 应用get和set方法访问。默认为false
unknownEnumName 表示该字段是一个Java的枚举类型
throwIfNull 如果为空值,抛出一个异常 默认为false
persisted 是否在数据库中存储这个领域 默认为true
format 指定某一特定领域的信息格式,如指定日期字符串的格式
unique 唯一约束,默认为false
uniqueCombo 唯一行,该行内所有字段成为一个唯一约束,如有firstName 和 lastName两个字段,为"张"和"梅",那么该表内不可再插             入"张","梅",   但你可插入"张","全梅"。
index 是否建立索引 默认为false
uniqueIndex 唯一索引 默认为false
indexName 为这一领域的索引添加一个名字
uniqueIndexName 为这一领域的索引添加一个唯一的名字
foreignAutoRefresh 当查询到一个外键对象时,是否自动刷新 如 Order表中有Account外键对象,当返回Order的记录时是否也返回Account的记录,           默认为false
maxForeignAutoRefreshLevel 为了防止无限递归或者无限循环时 需要用到该属性设置自动刷新的最高级别
allowGeneratedIdInsert 插入一个ID字段是否覆盖它生成的ID的对象 默认为false
columnDefinition 定义列,默认情况下,数据库类型是用于自动生成所需的SQL来创建列,所以该属性并不常用
foreignAutoCreate 在插入一个有外键对象的对象时,是否自动插入这个外键对象
version 行版本 当一个对象被更新,以防止数据损坏多个实体时更新在同一时间进行的保护
  • 实例OrmLiteSqliteOpenHelper
public class SqlitOrmHelper extends OrmLiteSqliteOpenHelper {
    private static String SQL_NAME = "testSql.db";
    private static int SQL_VERSION = 1;

    public SqlitOrmHelper(Context context) {
        super(context, SQL_NAME, null, SQL_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase, ConnectionSource connectionSource) {
       //创建表格
        try {
            TableUtils.createTable(connectionSource, UserEntity.class);
        } catch (java.sql.SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, ConnectionSource connectionSource, int i, int i1) {

    }
}
  • 查/删/改操作
    • 首先获取它自带的dao文件
	SqlitOrmHelper sqlitOrmHelper = new SqlitOrmHelper(this);
try {
    Dao<UserEntity, ?> dao = sqlitOrmHelper.getDao(UserEntity.class);
}catch (SQLException e) {
    e.printStackTrace();
}
  • 插入
      Dao<UserEntity, ?> dao = sqlitOrmHelper.getDao(UserEntity.class);
      UserEntity userEntity = new UserEntity();
      userEntity.setName("张三orm");
      userEntity.setPwd("张三orm");
      userEntity.setAge("2");
      dao.create(userEntity);
  • 查询
      List<UserEntity> userEntities = dao.queryForAll();
      Log.d(BaseData.LOG_TOAST,"查询成功:"+userEntities.toString());
  • 删除:复杂操作
      DeleteBuilder<UserEntity, ?> userEntityDeleteBuilder = dao.deleteBuilder();
      userEntityDeleteBuilder.where().eq("name","张三orm");
      userEntityDeleteBuilder.delete();

你可能感兴趣的:(android,android,java)