第一行代码Android项目(1-7)

**

项目一

**

第三章 Android------- UI开发的控件和布局(实验三)

D4-D2-D6-AF-EE-3A (2026)
添加链接描述
转载链接:https://blog.csdn.net/qq_53063025/article/details/111145829

实验目的
在Android Studio上如何实现UI开发的控件和布局,开发的项目名称是UIWIidgetTest,如何用编译的代码来实现简单的控件和布局。

软件
Android Studio

实验步骤
1. TextView****在界面上显示一段文本信息
在这里插入图片描述

2. Button在界面上显示一个按钮
在这里插入图片描述

3**.EditText可编辑的文本,允许用户在控件里输入和编辑**

在这里插入图片描述

4**. ImageView在界面上显示图片**

在这里插入图片描述

  1. ProgressBar在界面上显示一个进度条

在这里插入图片描述

6**.AlertDialog在当前界面弹出一个对话框,不同于上面的,这个是在程序中写的**
在这里插入图片描述

7.ProgressDialog在当前界面弹出一个有进度条的对话框,也是在程序中完成

在这里插入图片描述

  1. 程序转换字符串

在这里插入图片描述

9.最后综合得出

在这里插入图片描述

10.在虚拟机上运行的效果
在这里插入图片描述

11**.在手机运行效果**

在这里插入图片描述

  1. 线性布局垂直方向布局vertical
    在这里插入图片描述

13.运行得效果
在这里插入图片描述

14.horizontal垂直方向布局
在这里插入图片描述

  1. 运行效果

在这里插入图片描述

16.layout_width水平宽度布局
在这里插入图片描述

17.运行效果
在这里插入图片描述

18.ListView的简单用法
在这里插入图片描述

19.public class FruitAdapter
在这里插入图片描述

20.fruit

在这里插入图片描述

21.LinearLayout
在这里插入图片描述

22.FruitAapter
在这里插入图片描述

23.在MainActivity中编写,初始化水果数据
在这里插入图片描述

  1. 最后运行效果

在这里插入图片描述

项目二

第六章 数据存储全方案

82-30-49-6B-2F-0D (2017 2004)
添加链接描述
一.文件储存

建立一个mylnnerdata后,activity_main_xml代码如下
在这里插入图片描述

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="数据的内部存储"
    android:textSize="22sp" />
<Button
    android:id="@+id/but_save"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="存储数据"
    android:textSize="22sp"/>
<Button
    android:id="@+id/but_read"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="读取数据"
    android:textSize="22sp"/>

MainActivity代码如下
在这里插入图片描述
package com.example.mylnnerdata;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;

/**

  • 主界面的逻辑代码
    */
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button but_save,but_read;//保持与读取按钮
    private Object FileInputStream;
    private String fileName = “mydb.text”;//文件名称
    // String strNr = “HelloWorld”;//要保存的数据

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

     but_save = findViewById(R.id.but_save);
     but_read = findViewById(R.id.but_read);
    
    
     but_save.setOnClickListener(this);
     but_read.setOnClickListener(this);
    

    }

    //点击处理方法
    @Override
    public void onClick(View v) {
    switch (v.getId()){
    case R.id.but_save://保存数据
    savaData();
    break;
    case R.id.but_read:
    readData();
    break;
    }

    }

    //保存数据的方法
    private void savaData() {
    // String fileName = “mydb.text”;//文件名称
    String strNr = “HelloWorld,I’m coming”;//要保存的数据
    FileOutputStream fos = null;

     try {
         fos = openFileOutput(fileName,MODE_PRIVATE);
         fos.write(strNr.getBytes());//将数据写入文件中去
    
         Toast.makeText(this, "保存数据成功", Toast.LENGTH_SHORT).show();
     } catch (Exception e) {
         e.printStackTrace();
     }finally {
         try {
             if (fos!=null){
                 fos.close();
             }
         }catch (Exception ex){
             ex.printStackTrace();
         }
     }
    

    }

    //读取数据的方法

    private void readData() {
    String strNr = “”;//要读取的内容变量
    // FileInputStream = null;
    InputStream fis = null;
    try {
    fis = openFileInput(fileName);//获取输入流对象
    byte[] buffer = new byte[fis.available()];//创建读取的缓冲对象
    fis.read(buffer); //将文件内容读取到缓冲区中去
    strNr = new String(buffer); //转换成字符串
    Toast.makeText(this, strNr, Toast.LENGTH_SHORT).show();//显示

     }catch (Exception ex){
         ex.printStackTrace();
     }finally {
         try {
             if (fis!=null) {
             } else {
                 fis.close();
             }
         }catch (Exception ex){
             ex.printStackTrace();
         }
     }
    

    }
    }

点击运行后结果如下(手机页面)
在这里插入图片描述

SharedPreferences储存

建立一个mylnnerdata后,activity_main_xml代码如下
在这里插入图片描述
在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="15dp"
    android:background="#ffffff">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="用户名"
        android:textSize="20dp" />

    <EditText
        android:id="@+id/et_uname"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:hint="请输入用户名"
        android:background="@null"/>
</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="15dp"
    android:background="#ffffff">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="密   码:"
        android:textSize="20dp" />

    <EditText
        android:id="@+id/et_upass"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:inputType="textPassword"
        android:hint="请输入密码"
        android:background="@null"/>
</LinearLayout>

<Button
    android:id="@+id/btn_login"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:text="登录"
    android:textSize="20sp"/>

首先建立好myspdata下再建立SPDataUtils和Userinfo
MainActivity代码如下

在这里插入图片描述
package com.example.myspdata;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

/**

  • 主界面逻辑代码

*/

public class MainActivity extends AppCompatActivity implements OnClickListener {
private Button btn_login;
private EditText et_uname,et_upass;//用户名与密码控件

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    initView();//初始化控件

    initData();//加载初始化的数据
}

//初始化控件
private void initView(){
    btn_login = findViewById(R.id.btn_login);
    et_uname = findViewById(R.id.et_uname);
    et_upass = findViewById(R.id.et_upass);

    btn_login.setOnClickListener(this);

}

//初始化界面数据
private void initData(){
    Userinfo user = SPDataUtils.getUserionfo(this);
    if (user!=null && !TextUtils.isEmpty(user.getUname())){
        et_uname.setText(user.getUname());
        et_upass.setText(user.getUpass());
    }
}

//点击事件处理

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btn_login://登录
            chkAndSaveData();
            break;
    }
}
/**
 * 检查登录数据并精选保存
 */
private void chkAndSaveData(){
    String uname = et_uname.getText().toString().trim();
    String upass = et_upass.getText().toString().trim();

    if (TextUtils.isEmpty(uname)){
        showMsg("请输入用户名信息");
    }else if (TextUtils.isEmpty(upass)){
        showMsg("请输入密码信息");
    }else {
        boolean flag = SPDataUtils.saveUserInfo(this,uname,upass);
        if (flag){
            showMsg("保存数据成功");
        }else {
            showMsg("保存数据失败");
        }
    }
}

//显示信息的方法
private void showMsg(String msg){
    Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
}
}

SPDataUtils代码如下
在这里插入图片描述

package com.example.myspdata;

import android.content.Context;
import android.content.SharedPreferences;

/**

  • 使用sharePreferences实现数据的存取的工具类
    */
    public class SPDataUtils {
    private static final String mFileName = “mydata”;//文件名称

    /**

    • 保存用户信息
    • @param context 上下文件信息
    • @param uname 用户名
    • @param upass 密码
    • @return boolean 结果
      */

    static boolean saveUserInfo(Context context, String uname, String upass){
    boolean flag = false;
    SharedPreferences sp = context.getSharedPreferences(mFileName,Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sp.edit();
    editor.putString(“uname”,uname);
    editor.putString(“upass”,upass);
    editor.commit();
    flag = true;
    return flag;
    }

    /**

    • 获取用户信息的方法

    • @param context 调用的上下文

    • @return 返回Userinfo 的实例
      */
      public static Userinfo getUserionfo(Context context){
      Userinfo user = null;
      SharedPreferences sp = context.getSharedPreferences(mFileName,Context.MODE_PRIVATE);
      String uname = sp.getString(“uname”, null);
      String upass = sp.getString(“upass”, null);

      user = new Userinfo();
      user.setUname(uname);
      user.setUpass(upass);
      return user;

    }

}

Userinfo代码如下
在这里插入图片描述
package com.example.myspdata;

/**

  • 用户信息实体类
    */
    public class Userinfo {
    private String uname;
    private String upass;

    public Userinfo() {
    }

    public Userinfo(String uname, String upass) {
    this.uname = uname;
    this.upass = upass;
    }

    public String getUname() {
    return uname;
    }

    public void setUname(String uname) {
    this.uname = uname;
    }

    public String getUpass() {
    return upass;
    }

    public void setUpass(String upass) {
    this.upass = upass;
    }
    }

结果如下(手机上)
在这里插入图片描述

项目三

第七章

跨程序共享数据——实现拨打电话与查看联系人

添加链接描述
F8-A2-D6-D5-82-7B(2020)

文章目录

第一章 程序运行时申请权限
第二章 拨打电话“10086”
第三章 读取系统联系人

前言

本次我们主要学习跨程序实现共享数据,在模拟机上运行出可以实现拨打电话,实现查看联系人

一、程序运行时申请权限

android的权限机制并不是什么新鲜事物,从系统的第一个版本就已经存在了。首先新建一个RuntimePermission Test项目,我们就在这个项目的基础上来学习运行时权限的使用方法。这里我们使用CALL-PHONE这个权限来讲解,CALL-PHONE这个权限时编写拨打电话功能的时候需要声明的,因为拨打电话会涉及用户手机资费问题,因而被列为了危险权限。新建好项目后我们修改activity_main.xml布局文件,如下;
在这里插入图片描述
我们在布局文件中只是定义了一个按钮,当点击按钮时就去触发拨打电话的逻辑。接着修改MainActivity中的代码,如下;
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201213191751158.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzUzMDY2MTcx,size_16,color_FFFFFF,t_70
接下来修改AndroidManifest.xml文件,在其中声明如下权限:
在这里插入图片描述

二、 拨打电话“10086”

上面我们已经把拨打电话权限打开,这样拨打电话的功能实现了,并且在低于Android6.0系统的手机上都是可以正常运行的,但是如果在6.0或者更高版本系统的手机运行,点击Make Call按钮就没有任何效果,这是我们在继续修改MainActivity中的代码,如下;
在这里插入图片描述
在这里插入图片描述
现在重新点击运行一下程序,点击MakeCall 按钮,如下;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以把”10086“电话换成其他号码也可以实现的哟!

三、 读取系统联系人

由于我们一直使用的都是模拟器,电话簿里面没有联系人存在,所以现在需要自己手动添加几个,以便一会儿进行读取,打开电话簿程序,如下;
在这里插入图片描述
可以看到目前没有联系人,我们可以通过点击”+“号添加联系人,以下我添加了两个联系人,如下;
在这里插入图片描述
在这里插入图片描述
准备工作做好后,现在新建一个项目,还是先来布局文件,修改activity_xml中的代码,如下;
在这里插入图片描述
接着修改MainActivity中的代码,如下;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
记得还要修改联系人的权限,修改AndroidManifest.xml中的代码,如下;
在这里插入图片描述
代码改完后就可以点击运行了,运行结果如下;
在这里插入图片描述

总结

通过这次学习实现了跨程序共享数据,拨打电话,查看联系人,如何打开权限,也是不小的收获。

项目四

第八章简单运用手机多媒体

添加链接描述

简单运用手机多媒体 F8-94-C2-44-C2-AD(2025)


一、调用摄像头和相册

1.调用摄像头拍照

activity_main.xml文件,添加一个Button用于打开摄像头进行拍照,添加ImageView用于将图片显示出来。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
  <Button
      android:id="@+id/take_photo"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="take photo"/>
    <ImageView
        android:id="@+id/picture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>
</LinearLayout>

MainActivity文件中代码

public class MainActivity extends AppCompatActivity {
    public static final int TAKE_PHOTO = 1;
private ImageView picture;
//图片本地的真实路径
    private Uri imageUri;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button takePhoto = (Button) findViewById(R.id.take_photo);
        picture = (ImageView) findViewById(R.id.picture);
        takePhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
//用于存放拍下的照片
                File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
                try {
                    if(outputImage.exists()){
                       outputImage.delete();
                    }
                    outputImage.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if(Build.VERSION.SDK_INT >= 24){
//File对象转换为Uri标识对象
                    imageUri = FileProvider.getUriForFile(MainActivity.this, "com.launcher.cameraalbumtest.fileprovider", outputImage);
                }else{
//指定图片的输出地址
                    imageUri = Uri.fromFile(outputImage);
                }
//隐式Intent,启动相机程序
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                startActivityForResult(intent, TAKE_PHOTO);
            }
        });
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode){
            case TAKE_PHOTO:
                if(resultCode == RESULT_OK){
                    try {
//拍照成功后显示图片
                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                        picture.setImageBitmap(bitmap);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
                break;
            default:
                break;
        }
    }
}

应用关联缓存目录:

    SD卡中专门用于存放当前应用缓存数据的位置,调用getExternalCacheDir()方法可以得到这个目录,具体路径:/sdcard/Android/data/<package name>/cache。

    Android 6.0以后读写SD卡被列为危险权限,如果将图片存放到其他目录要进行运行时权限处理,使用应用关联缓存目录可以跳过这一步。

    Android 7.0以后,直接使用本地真实路径的Uri被认为是不安全的,会抛出FileUriExposedException异常,而使用FileProvider是一种特殊的内容提供器,它使用了和内容提供器类似的机制对数据进行保护,可以选择性的封装过的Uri共享给外部,从而提高应用的安全性。

2.从相册中选择照片

布局文件,放一个Button和一个ImageView,Button用来启动拍照图片并截图,ImageView用来显示截图后的照片,activity_main.xml代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_photo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Take Photo" />

    <Button
        android:id="@+id/btn_album"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Choose from Album" />

    <ImageView
        android:id="@+id/img_photo"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center_horizontal" />

</LinearLayout>

MainActivity.java代码:

package com.test.photo;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

//import com.test.R;

import androidx.core.content.FileProvider;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * Created by Administrator on 2016/5/4 0004.
 */
public class MainActivity extends Activity {
    private static final int TAKE_PHOTO = 1;
    private static final int CROP_PHOTO = 2;
    private Button btnPhoto;
    private ImageView imgPhoto;
    private Uri imgUri;
    private Button btnAlbum;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_photo);
        btnPhoto = (Button) findViewById(R.id.btn_photo);
        imgPhoto = (ImageView) findViewById(R.id.img_photo);
        btnAlbum = (Button) findViewById(R.id.btn_album);
        btnAlbum.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//创建一个File对象,用于存储摄像头拍下的图片,这里命名为outputImg.jpg,并将它存放在手机SD卡的根目录下
//Environment.getExternalStorageDirectory()这个方法就是获取到手机SD卡的根目录
                File outputImage = new File(Environment.getExternalStorageDirectory(), "output_image.jpg");
                try {
                    if (outputImage.exists()) {
                        outputImage.delete();
                    }
                    outputImage.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
//调用Uri.fromFile 将File对象转化成Uri对象,这个Uri对象标识着outputImg.jpg这张图片的唯一地址
                imgUri = Uri.fromFile(outputImage);
//构建Intent对象,Intent的action指定为android.media.action.GET_CONTENT允许用户选择特殊的数据并返回
                Intent intent = new Intent("android.intent.action.GET_CONTENT");
//查看类型为image的数据
                intent.setType("image/*");
//设置该图片可裁剪
                intent.putExtra("crop", true);
//设置该图片可缩放
                intent.putExtra("scale", true);
//调用Intent的putExtra指定图片的输出地址,这边为刚刚得到的Uri(即imgUri)对象
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
                startActivityForResult(intent, CROP_PHOTO);
            }
        });

        btnPhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//创建一个File对象,用于存储摄像头拍下的图片,这里命名为outputImg.jpg,并将它存放在手机SD卡的根目录下
//Environment.getExternalStorageDirectory()这个方法就是获取到手机SD卡的根目录
                File outputImg = new File(Environment.getExternalStorageDirectory(), "tempImg.jpg");
                try {
                    if (outputImg.exists()) {
                        outputImg.delete();
                    }
                    outputImg.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
//调用Uri.fromFile 将File对象转化成Uri对象,这个Uri对象标识着outputImg.jpg这张图片的唯一地址
                imgUri = Uri.fromFile(outputImg);
//构建Intent对象,Intent的action指定为android.media.action.IMAGE_CAPTURE表示使用系统的拍照功能
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
//调用Intent的putExtra指定图片的输出地址,这边为刚刚得到的Uri(即imgUri)对象
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
                startActivityForResult(intent, TAKE_PHOTO); //启动活动
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case TAKE_PHOTO:
                if (resultCode == RESULT_OK) {
//构建Intent对象,Intent的action指定为com.android.camera.action.CROP 表示使用系裁剪图片
                    Intent intent = new Intent("com.android.camera.action.CROP");
//查看类型为image的数据
                    intent.setDataAndType(imgUri, "image/*");
//设置该图片可缩放
                    intent.putExtra("scale", true);
//调用Intent的putExtra指定图片的输出地址,这边为刚刚得到的Uri(即imgUri)对象
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
                    startActivityForResult(intent, CROP_PHOTO);//启动裁剪程序
                }
                break;
            case CROP_PHOTO:
                if (resultCode == RESULT_OK) {
                    try {
                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imgUri));
                        imgPhoto.setImageBitmap(bitmap);//将裁剪后的图片显示出来
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
                break;
        }
    }
}

AndroidManifest.xml文件中声明权限:

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

二、播放多媒体文件

在安卓中播放音频文件一般用 MediaPlayer类来实现,播放视频文件主要用 VideoView类来实现。

(一)MediaPlayer 常用方法:

MediaPlayer构造方法
create创建一个要播放的多媒体
getCurrentPosition得到当前播放位置
getDuration得到文件的时间
getVideoHeight得到视频的高度
getVideoWidth得到视频的宽度
isLooping是否循环播放
isPlaying是否正在播放
pause暂停
prepare准备(同步)
prepareAsync准备(异步)
release释放MediaPlayer对象相关的资源
reset重置MediaPlayer对象为刚刚创建的状态
seekTo指定播放的位置(以毫秒为单位的时间)
setAudioStreamType设置流媒体的类型
setDataSource设置多媒体数据来源(位置)
setDisplay设置用SurfaceHolder来显示多媒体
setLooping设置是否循环播放
setOnButteringUpdateListener网络流媒体的缓冲监听
setOnErrorListener设置错误信息监听
setOnVideoSizeChangedListener视频尺寸监听
setScreenOnWhilePlaying设置是否使用SurfaceHolder来保持屏幕显示
setVolume设置音量
start开始播放
stop停止播放

(二) VideoViewMediaPlaer也比较类似,主要有以下常用方法:

MediaPlayer构造方法
setVideoPath()设置要播放的视频文件的位置。
start()开始或继续播放视频。
pause()暂停播放视频。
resume()将视频重头开始播放。
seekTo()从指定的位置开始播放视频。
isPlaying()判断当前是否正在播放视频。
getDuration()获取载入的视频文件的时长。

1. 播放音频

activity_main.xml文件代码

package com.dak.administrator.firstcode.multi_media;
 
import android.Manifest;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
 
import com.dak.administrator.firstcode.R;
 
import java.io.File;
import java.io.IOException;
 
public class MediaActivity extends AppCompatActivity implements View.OnClickListener {
 
    private MediaPlayer mediaPlayer = new MediaPlayer();
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_media);
 
        Button play = findViewById(R.id.play);
        Button pause = findViewById(R.id.pause);
        Button stop = findViewById(R.id.stop);
 
        play.setOnClickListener(this);
        pause.setOnClickListener(this);
        stop.setOnClickListener(this);
 
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }else {
            initMediaPlayer();
        }
 
    }
 
    private void initMediaPlayer() {
        try {
            File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");//music.mp3不存在
            mediaPlayer.setDataSource(file.getPath());
            mediaPlayer.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            initMediaPlayer();
        }else {
            Toast.makeText(this, "请获取存储权限", Toast.LENGTH_SHORT).show();
            finish();
        }
    }
 
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.play:
                if (!mediaPlayer.isPlaying()) {
                    mediaPlayer.start();
                }
                break;
 
            case R.id.pause:
                if (mediaPlayer.isPlaying()) {
                    mediaPlayer.pause();
                }
                break;
 
            case R.id.stop:
                if (!mediaPlayer.isPlaying()) {
                    mediaPlayer.reset();
                    initMediaPlayer();
                }
                break;
        }
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
 
    }
}

activity_main.xml文件代码:

<?xml version="1.0" encoding="utf-8"?>
<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="com.dak.administrator.firstcode.multi_media.MediaActivity">
 
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/play"
        android:text="play"
        />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/pause"
        android:text="pause"
        />
 
    <Button
        android:id="@+id/stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="stop" />
 
 
</LinearLayout>

2.播放视频

MainActivity.java文件代码

package com.dak.administrator.firstcode.multi_media;
 
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.widget.VideoView;
 
import com.dak.administrator.firstcode.R;
 
import java.io.File;
 
public class VideoActivity extends AppCompatActivity implements View.OnClickListener {
 
 
    private VideoView videoView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video);
 
        Button play = findViewById(R.id.play);
        Button pause = findViewById(R.id.pause);
        Button replay = findViewById(R.id.replay);
 
        videoView = findViewById(R.id.video_view);
 
        play.setOnClickListener(this);
        pause.setOnClickListener(this);
        replay.setOnClickListener(this);
 
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }else {
            initVideoPath();
        }
    }
 
    private void initVideoPath() {
        File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
        videoView.setVideoPath(file.getPath());
 
    }
 
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            initVideoPath();
        }else {
            Toast.makeText(this, "请获取存储权限", Toast.LENGTH_SHORT).show();
            finish();
        }
    }
 
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.play:
                if (!videoView.isPlaying()) {
                    videoView.start();
                }
                break;
            case R.id.pause:
                if (videoView.isPlaying()) {
                    videoView.pause();
                }
                break;
            case R.id.replay:
                if (videoView.isPlaying()) {
                    videoView.resume();//重新播放
                }
                break;
        }
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
 
        if (videoView != null) {
            videoView.suspend();//释放资源
        }
    }
}

activity_main.xml文件代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
 
        <Button
            android:id="@+id/play"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="play" />
 
        <Button
            android:id="@+id/pause"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="pause" />
 
        <Button
            android:id="@+id/replay"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="replay" />
 
    </LinearLayout>
 
    <VideoView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/video_view"
        />
</LinearLayout>

三、程序运行

1.在模拟器上运行

(1)选择下载好的模拟器,点击运行
在这里插入图片描述
(2)模拟器页面布局
在这里插入图片描述
(3)模拟器运行结果,点击按下Take Photo按钮,打开模拟器相机
在这里插入图片描述
(4)点击按下Choose from Album按钮,打开模拟器相册
在这里插入图片描述

2.在真实机上运行

(1)我本人用的手机型号是小米手机,到设置打开手机的开发者选项,由于各个手机厂商的打开方式都不同,下面列出一些常用手机:(如有错误的或是打不开的百度搜索一下)

小米手机:连续点击三下"MIUI 版本"
华为手机:连续点击"版本号"多次,直到屏幕提示已进入开发者模式。
三星手机:连续快速点击多次“软件信息”按钮,直到屏幕提示已进入开发者模式。
OPPO手机:连续点击"版本号"多次
VIVO手机:连续点击"软件版本号"多次
魅族手机:连续点击"版本号"多次
锤子手机:连续点击"软件版本"多次
努比亚手机:连续点击"版本号"多次

(2)进入开发者选项,打开USB调试,部分手机还需要打开USB安装。而我的就一定要打开才能安装,刚开始还没打开时USB安装时,怎么都安装不上,在Android Studio软件还报了一堆错误,通过自己查找资料、翻译,最终自己遇到的这问题解决了。
在这里插入图片描述
(3)手机运行结果
在这里插入图片描述

项目五

第十章
添加链接描述
D0-7E-35-BF-5D-79(2014)

目录

1.线程的基本用法
2.在子线程中更新UI
3.解析异步消息处理机制
4.使用AsyncTask
**

一.线程的基本用法
在这里插入图片描述
二.在子线程中更新UI
这个时候我们就需要借助Java了
我们在java里面的activity里修改代码
代码如下

在这里插入图片描述
在这里插入图片描述

下就可以看到运行程序,程序崩溃了
然后修改代码

在这里插入图片描述
就可以看到成功了
三.解析异步消息处理机制

在这里插入图片描述
四.使用AsyncTask
在这里插入图片描述
在这里插入图片描述
到这里我们就结束了,上面就是我们的过程,希望能有帮助
添加链接描述

服务的基本用法

D0-7E-35-BF-5D-79(2014)

1.定义一个服务
2.启动和停止服务
3.活动和服务进行通信
一.定义一个服务
我们先建立一个Myservice项目

在这里插入图片描述
然后修改Myservice代码
在这里插入图片描述

二.启动和停止服务
定义好服务以后,我们就可以启动和停止这个服务了
首先修改activity的代码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
到这里就实现了
三.活动和服务进行通信
首先修改Myservice

在这里插入图片描述
在这里插入图片描述
现在是main activity代码
在这里插入图片描述
在这里插入图片描述
现在就可以运行一下程序了
在这里插入图片描述
运行成功
希望对大家有点帮助

项目六

第一行代码 第十一章基于位置的服务
98-8D-46-9C-DC-2C
(2022)
添加链接描述
转载连接:https://blog.csdn.net/m0_53046928/article/details/111122878

一、基于位置的服务简介

基于位置的服务简称LBS,随着移动互联网的兴起,这个技术在最近的几年里十分火爆。其实它本身并不是什么时髦的技术,主要的工作原理就是利用无线电通讯网络或GPS等定位方式来确定出移动设备所在的位置,而这种定位技术早在很多年前就已经出现了。
基于位置的服务,主要的工作原理是利用无线电通讯网络或 GPS 等定位方式来确定出移动设备所在的位置。LBS 所围绕的核心就是要确定出用户所在的位置。
通常有两种技术:
GPS 定位:
 基于手机内置的 GPS 硬件直接和卫星交互来获取当前的经纬度信息,精确度高,但只能室外使用,室内基本无法接收到卫星的信号。

网络定位:
 根据手机当前网络附近的三个基站进行测速,以此计算出手机和每个基站之间的距离,再通过三角定位确定一个大概位置,精确度一般,但室内外均可使用。

二、申请API Key

1、要在应用程序中使用百度LBS功能,需申请一个API Key(需有百度账号)。登录百度账号,打开http://developer.baidu.com/user/reg网址,填写注册信息
在这里插入图片描述

2、点击提交,进入验证邮箱界面
在这里插入图片描述
3、接着点击“去我的邮箱”,将会进入到我们刚才填写的邮箱当中,这时收件箱中应该会有一封刚刚收到的邮件,这就是百度发送给我们的验证邮件,点击邮件当中的链接就可以完成注册了。
4、接着访问http://lbsyun.baidu.com/apiconsole/key,同意百度开发者协议:

在这里插入图片描述
5、点击创建应用
在这里插入图片描述
那么,这个发布版SHA1和开发版SHA1又是个什么东西呢?这是我们申请APIKey所必须填写的一个字段,它指的是打包程序时所用签名文件的SHA1指纹。
一、通过Android Studio获取

  1. 打开Android Studio,进入Terminal工具,如下图所示:在这里插入图片描述
  2. 输入命令行和密码,即可获取SHA1等信息;

命令行:keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey (注意目录选择、开发版本、发布版本等问题)

密码:原始密码一般为android,开发者根据实际情况填写。

二、使用 keytool(jdk自带工具)获取

  1. 运行进入控制台Windows:运行 -> 输入cmd -> 确定。

  2. 在控制台内,定位到.android文件夹,输入cd .android
    在这里插入图片描述

  3. 输入命令行和密码,获取SHA1等信息
    命令行:keytool -list -v -keystore debug.keystore;
    密码:原始密码一般为android,开发者根据实际情况填写。
    注意:

调试版本使用 debug.keystore,命令为:keytool -list -v -keystore debug.keystore。 发布版本使用 apk 对应的 keystore,命令为:keytool -list -v -keystore apk 的 keystore。
在这里插入图片描述
注意:一些电脑需要手动输入密钥,一些可以直接点击回车键。
适用于使用Android Studio开发工具的开发者。
三、包名的获取
Android Studio可以通过applicationId配置包名,如果配置了build.gradle文件,包名应该以applicaionId为准,防止build.gradle中的applicationId与 AndroidMainfest.xml中的包名不同,导致AK鉴权失败。
在这里插入图片描述
此时已完成了相应的注册填写步骤

三、使用百度定位

现在正是趁热打铁的好时机,新建一个LBSTest项目,包名应该就会自动被命名为com.example My11。

1.准备LBS SDK

先将百度 LBS 开放平台的 SDK 准备好,下载地址:http://lbsyun.baidu.com/sdk/download
如果链接打不开,也可以到上一步创建应用哪里,点击开发文档—Android 地图 SDK–产品下载
在这里插入图片描述

点击去下载,就会出现如图所示:
在这里插入图片描述
本章会用到基础地图和基础定位这两个 SDK,下载完后对该压缩包解压,libs 目录里就有我们所需要的一切了:
在这里插入图片描述

压缩包libs目录下的内容

下面把 libs 目录里的内容拷贝到我们的项目中:
 (1)把 BaiduLBS_Android.jar 拷贝到项目 app 模块中的 libs 目录:
将 jar 包放置到 libs 目录中
(2)展开 src/main 目录,右击该目录→New→Directory,创建一个名为 jniLibs 的目录,用来存放 so 包,然后把压缩包里的其他所以目录直接复制到这里:

在这里插入图片描述

将 so 文件放置到 jniLibs 目录中
另外,记得点击顶部工具栏中的 Sync 按钮(下图中最左边的按钮)将 BaiduLBS_Android.jar 添加到当前项目的引用中。(如果无法引用的话可以到build.gradle里看看是否有这一段话在这里插入图片描述
)没有的话右键点击放入的’jar’包选择add as library

2、确定自己位置的经纬度

(1)首先修改activity_main.xml中的代码,如下所示:

<LinearLayout xmlns :android="http:/ /schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent""android:layout_height="match_parent" >
<TextView
android :id="@+id/position_text_views"-android : layout_width="wrap_content"
android : layout_height="wrap_content" f>
</LinearLayout

(2)然后修改AndroidManifest.xml文件中的代码,如下所示:
添加所需权限

<!-- 百度 LBS 相关权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

(3)再注册一个百度 LBS SDK 中的服务

 <application
        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/Theme.My11">
        <meta-data
            **android:name="com.baidu.lbsapi.API_KEY"
            android:value="xoEORL5N4VMNHDr7rzQV6bqWAknpT2Zd" />**

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        **<service android:name="com.baidu.location.f" 
            android:enabled="true"
            android:process=":remote">
        </service>**
    </application>
</manifest>

其中每个权限都是百度LBS SDK内部要用的,标签name部分是固定的value部分则是申请到的API Key.最后注册了LBS SDK中的服务
例如:android:value=“xoEORL5N4VMNHDr7rzQV6bqWAknpT2Zd”

(4)修改MainActivity:

public class MainActivity extends AppCompatActivity {

    public LocationClient mLocationClient;
    private TextView positionText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLocationClient = new LocationClient(getApplicationContext());
        mLocationClient.registerLocationListener(new MyLocationListener());
        setContentView(R.layout.activity_main);
        positionText = (TextView) findViewById(R.id.positions_text_view);
        List<String> permissionList = new ArrayList<>();
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.
                permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_DENIED) {
            permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.
                permission.READ_PHONE_STATE) != PackageManager.PERMISSION_DENIED) {
            permissionList.add(Manifest.permission.READ_PHONE_STATE);
        }
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.
                permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
        if (!permissionList.isEmpty()) {
            String[] permission = permissionList.toArray(new String[0]);
            ActivityCompat.requestPermissions(MainActivity.this, permission, 1);
        } else {
            requestLocation();
        }
    }

    private void requestLocation() {
        mLocationClient.start();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull  String[] permissions,
                                           @NonNull  int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0) {
                    for (int result : grantResults) {
                        if (result != PackageManager.PERMISSION_GRANTED) {
                            Toast.makeText(this, "必须同意所有权限才能使用本程序",
                                    Toast.LENGTH_SHORT).show();
                            finish();
                            return;
                        }
                    }
                    requestLocation();
                } else {
                    Toast.makeText(this, "发生未知错误", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
        }
    }

    public class MyLocationListener implements BDLocationListener {

        @Override
        public void onReceiveLocation(BDLocation Location) {
            StringBuilder currentPosition = new StringBuilder();
            currentPosition.append("纬度:").append(Location.getLatitude()).append("\n");
            currentPosition.append("经线:").append(Location.getLongitude()).append("\n");
            currentPosition.append("定位方式:");
            if (Location.getLocType() == BDLocation.TypeGpsLocation) {
                currentPosition.append("GPS");
            } else if (Location.getLocType() == BDLocation.TypeNetWorkLocation) {
                currentPosition.append("网络");
            }
            positionText.setText(currentPosition);
        }
    }
}

(5)运行程序,允许权限,移动手机查看变化

在这里插入图片描述

3、选择定位模式

GPS功能必须要由用户主动去开启才行,不然任何应用程序都无法使用GPS获取到手机当前的位置信息。

共有3种模式:
(1)Hight_Accuracy 高精度模式(默认模式),会在GPS信号正常的情况下优先使用GPS定位,在无法接收GPS信号时用网络定位。

(2)Battery_Saving 节电模式,只会使用网络定位。

(3)Device_Sensors 传感器模式,只会使用GPS定位。

强制使用Gps进行定位。

option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);

4、看得懂的位置信息

百度LBS SDK提供了很好的支持,只需调用一些简单接口聚能得到当前位置各种丰富信息。修改MainActivity:
在这里插入图片描述

option.setIsNeedAddress(true);

在这里插入图片描述

currenPosition.append("国家:").append(location.getCountry()).
                    append("\n");
            currenPosition.append("省:").append(location.getProvince()).
                    append("\n");
            currenPosition.append("市:").append(location.getCity()).
                    append("\n");
            currenPosition.append("区:").append(location.getDistrict()).
                    append("\n");
            currenPosition.append("街道:").append(location.getStreet()).
                    append("\n");

在这里插入图片描述

5、使用百度地图

需要用到百度提供的自定义控件 MapView

<com.baidu.mapapi.map.MapView
        android:id="@+id/bmapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true"
        android:focusable="true" />

MainActivity处:
在这里插入图片描述
在这里插入图片描述

private MapView mapView;
SDKInitializer.initialize(getApplicationContext());
mapView = (MapView) findViewById(R.id.bmapView);
  @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume();
    }
    @Override
    protected  void onPause() {
        super.onPause();
        mapView.onPause();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLocationClient.stop();
        mapView.onDestroy();
        baiduMap.setMyLocationEnabled(false);
    }

在这里插入图片描述

6、移动到自己的位置

百度 LBS SDK 的 API 中提供了一个** BaiduMap** 类,是地图的总控制器,有了它就能对地图进行各种各样的操作了。获取其实例如下:

BaiduMap baiduMap = mapView.getMap();

百度地图将缩放级别的取值范围限定在3到19之间,也可取小数点位,值越大地图显示信息越精细,如把缩放级别设置成12.5,可以这样写:

MapStatusUpdate update = MapStatusUpdateFactory.zoomTo(12.5f);
baiduMap.animateMapStatus(update);

若要让地图移动到某个经纬度上,可以借助 LatLng 类,如将地图移动到北纬39.915°、东经116.404°,可以这样写:

LatLng ll = new LatLng(39.915,116.404);
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);

接下来实现下 “移动到我的位置” 这个功能,修改活动中代码如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

四、总结

郭霖总结:不得不说,本章中学到的知识应该还算是蛮有趣的吧?在这次的Android特色开发环节中我们主要学习了基于位置服务的工作原理和用法,借助百度提供的LBS SDK,我们可以随时确定自己当前位置的经纬度,并且还能获取到具体的省、市、区、街道等地址。之后又学习了百度地图的用法,不仅成功地将地图信息显示了出来,还综合利用了前面所学到的定位技术实现了一个较为完整的例子。

除了基于位置的服务之外,本章Git时间中继续对Git的用法进行了更深一一步的探究, 使得我们对分支和远程版本库的使用都有了一一定层次的了解。

我的总结:
这章本人并没有写任何的代码,(代码来源:第一行代码android)而是进行了通读.

项目七

第一行代码 第十二章(最佳UI体验) F8-94-C2-44-C2-AD(2025)
添加链接描述


最佳UI体验

其实长久以来,大多数人都认为Android系统的UI并不算美观,至少没有 iOS系统的美观。以至于很多IT公司在进行应用界面设计的时候,为了保证双平台的统一性,强制要求Android端的界面风格必须和 iOS端一致。同一个操作系统中各个应用之间的界面统一性要远比一个应用在双平台的界面统一性重要得多,只有这样,才能给使用者带来更好的用户体验。
但问题在于,Android标准的界面设计风格并不是特别被大众所接受,很多公司都觉得自己完全可以设计出更加好看的界面,从而导致Android平台的界面风格长期难以得到统一。在2014年Google IO大会上重磅推出了一套全新的界面设计语言-—-—Material Design。
本章我们就将对Material Design进行一次深入的学习。

一、什么是 Material Design

Material Design是由谷歌的设计工程师基于优秀的设计原则,结合丰富的创意和科学技术所发明的一套全新的界面设计语言,包含了视觉、运动、互动效果等特性。

二、布局设计

1.布局代码分别如下
在这里插入图片描述
代码如下:

<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:id="@+id/toolbar"
                android:background="?attr/colorPrimary"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_scrollFlags="scroll|enterAlways|snap"
                />
            <!-- layout_scrollFlags :scroll表示向上滚动时Toolbar滚动并实现隐藏,enenterAlways表示向下滚动时Toolabr向下滚动并重现
                   snap表示当Toolbar还没有完全隐藏或显示时,根据当前滚动的距离,选择隐藏还是显示 -->
        </com.google.android.material.appbar.AppBarLayout>
        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/srf"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <androidx.recyclerview.widget.RecyclerView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/recyclerview"
                />

        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>


        <!-- 指定布局行为 -->
        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/fab"
            android:src="@drawable/pear"
            android:layout_gravity="bottom|right"
            android:layout_margin="16dp"
            app:elevation="8dp"

            />
        <!-- elevation给FloatingActionButton指定一个高度值,高度值越大,投影范围越大,投影效果越淡 -->
    </androidx.coordinatorlayout.widget.CoordinatorLayout>


    <com.google.android.material.navigation.NavigationView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_view"
        android:layout_gravity="start"
        app:menu="@menu/circleimagemenu"
        app:headerLayout="@layout/headerlayout"/>

</androidx.drawerlayout.widget.DrawerLayout>

activity_main2.xml代码如下:

<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:id="@+id/appbar">
        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:contentScrim="@color/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
            <!--exitUntilCollapsed随着滚动完成折叠之后就保留在界面上,不在移出屏幕 -->
            <ImageView
                android:id="@+id/image2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"/>
            <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:id="@+id/toolbar2"
                app:layout_collapseMode="pin"/>
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>
    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="15dp"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                android:layout_marginTop="35dp"
                app:cardCornerRadius="4dp">
                <TextView
                    android:id="@+id/textview2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp"
                    />

            </androidx.cardview.widget.CardView>
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@drawable/pear"
        app:layout_anchor="@id/toolbar2"
        app:layout_anchorGravity="bottom|end"/>
    <!--layout_anchor设置瞄点 -->



</androidx.coordinatorlayout.widget.CoordinatorLayout>

headerlayout.xml代码如下:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="180dp">          <!-- 180dp是NavigationView比较合适的高度 -->
    <de.hdodenhof.circleimageview.CircleImageView
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:id="@+id/header_image"
        android:src="@drawable/pear"
        android:layout_centerInParent="true"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/header_textView1"
        android:text="嘿嘿"
        android:textSize="14sp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:textColor="#191515"
        />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/header_textView2"
        android:text="哎呀"
        android:textSize="14sp"
        android:layout_above="@id/header_textView1"
        android:textColor="#150A0A"
        />


</RelativeLayout>

item.xml代码

<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="5dp"
    app:cardCornerRadius="4dp"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:id="@+id/item_image"
            android:scaleType="centerCrop"/>      <!-- 指定图片的缩放模式,他可以让图片保持原有比例填充ImageView,并裁掉超出部分 -->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/item_textview"
            android:layout_gravity="center_horizontal"
            android:layout_margin="5dp"
            android:textSize="16sp"/>
    </LinearLayout>


</androidx.cardview.widget.CardView>

三、程序设计

1.分别创建3个文件夹如(Fruit)、(MainActivity2)、 (Mydapt)
在这里插入图片描述
MainActivity代码


import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.navigation.NavigationView;
import com.google.android.material.snackbar.Snackbar;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;




public class MainActivity extends AppCompatActivity {
    DrawerLayout drawerLayout;
    private SwipeRefreshLayout swipeRefreshLayout;
    private Mydapt adapt;
    private List<Fruit> list = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        NavigationView navigationView = (NavigationView)findViewById(R.id.nav_view);
        Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);

        setSupportActionBar(toolbar);
        drawerLayout = (DrawerLayout)findViewById(R.id.drawerLayout);
        ActionBar actionBar = getSupportActionBar();
        if(actionBar != null){
            actionBar.setDisplayHomeAsUpEnabled(true);      //让导航按钮显示出来
            actionBar.setHomeAsUpIndicator(R.mipmap.ic_launcher);   //设置导航按钮图标,默认是返回的图标
        }
        navigationView.setCheckedItem(R.id.item_cgl1);      //设置菜单项的默认选中
        //对菜单项设置监听
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
                drawerLayout.closeDrawers();        //将滑动菜单关闭
                return true;
            }
        });
        //FloatingActionButton点击事件
        FloatingActionButton floatingActionButton = (FloatingActionButton)findViewById(R.id.fab);
        floatingActionButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Snackbar.make(v,"Data delete",Snackbar.LENGTH_SHORT)
                        .setAction("Undo", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Toast.makeText(MainActivity.this,"click",Toast.LENGTH_SHORT).show();
                            }
                        })
                        .show();

            }
        });
        //RecyclerView
        addlist();
        RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerview);
        GridLayoutManager manager = new GridLayoutManager(MainActivity.this,2);
        adapt = new Mydapt(list);
        recyclerView.setLayoutManager(manager);
        recyclerView.setAdapter(adapt);
        //下拉刷新:
        swipeRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.srf);
        swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);       //设置颜色
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                refreshFruits();
            }
        });

    }

    private void refreshFruits() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        addlist();
                        adapt.notifyDataSetChanged();
                        swipeRefreshLayout.setRefreshing(false);        //刷新事件结束,并隐藏刷新进度条
                    }
                });
            }
        }).start();
    }

    private void addlist() {
        list.clear();
        Fruit[] fruits = {new Fruit("grape",R.drawable.grape),new Fruit("orange",R.drawable.orange),
                new Fruit("pear",R.drawable.pear),new Fruit("watemelon",R.drawable.watemelon)};
        for(int i  =0; i < 50 ;i++){
            Random random = new Random();
            int index = random.nextInt(fruits.length);
            list.add(fruits[index]);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.toolbarmenu,menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.item1:
                break;
            case R.id.item2:
                break;
            case R.id.item3:
                break;
            case android.R.id.home:
                drawerLayout.openDrawer(GravityCompat.START);
        }
        return true;
    }
}

Fruit代码代码如下:


public class Fruit {
    private String Name;
    private int imageId;

    public Fruit(String name, int imageId) {
        Name = name;
        this.imageId = imageId;
    }

    public String getName() {
        return Name;
    }

    public int getImageId() {
        return imageId;
    }
}

MainActivity2代码


import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.google.android.material.appbar.CollapsingToolbarLayout;

public class MainActivity2 extends AppCompatActivity {
    public static final String FRUIT_NAME = "fruit_name";
    public static final String FRUIT_IMAGE_ID = "fruit_image_id";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        Intent intent = getIntent();
        String fruitName = intent.getStringExtra(FRUIT_NAME);
        int imageId = intent.getIntExtra(FRUIT_IMAGE_ID,0);

        Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar2);
        CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout)findViewById(R.id.collapsing_toolbar);
        ImageView imageView = (ImageView)findViewById(R.id.image2);
        TextView textView = (TextView)findViewById(R.id.textview2);
        setSupportActionBar(toolbar);
        ActionBar actionBar = getSupportActionBar();
        if(actionBar != null){
            actionBar.setDisplayHomeAsUpEnabled(true);
        }
        collapsingToolbarLayout.setTitle(fruitName);
        Glide.with(this).load(imageId).into(imageView);
        String fruitContent = geterateFruitContent(fruitName);
        textView.setText(fruitContent);
    }

    private String geterateFruitContent(String fruitName) {
        StringBuilder fruitContent = new StringBuilder();
        for(int i = 0;  i < 500; i++){
            fruitContent.append(fruitName);
        }
        fruitContent.reverse();
        return fruitContent.toString();
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case android.R.id.home:
                finish();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

Mydapt代码


import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;

import org.w3c.dom.Text;

import java.util.List;

public class Mydapt extends RecyclerView.Adapter<Mydapt.ViewHolder> {
    private List<Fruit> list;
    private Context mcontext;
    public Mydapt(List<Fruit> list) {
        this.list = list;
    }

    class ViewHolder extends RecyclerView.ViewHolder{
        CardView cardView;
        ImageView imageView;
        TextView textView;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            cardView = (CardView) itemView;
            imageView = itemView.findViewById(R.id.item_image);
            textView = itemView.findViewById(R.id.item_textview);
        }
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if(mcontext==null)
            mcontext = parent.getContext();
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
        final ViewHolder viewHolder = new ViewHolder(view);
        viewHolder.cardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = viewHolder.getAdapterPosition();
                Fruit fruit = list.get(position);
                Intent intent = new Intent(mcontext,MainActivity2.class);
                intent.putExtra(MainActivity2.FRUIT_NAME,fruit.getName());
                intent.putExtra(MainActivity2.FRUIT_IMAGE_ID,fruit.getImageId());
                mcontext.startActivity(intent);
            }
        });
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Fruit fruit = list.get(position);
        holder.textView.setText(fruit.getName());
        Glide.with(mcontext).load(fruit.getImageId()).into(holder.imageView);       //用Glide加载图片

    }

    @Override
    public int getItemCount() {
        return list.size();
    }


}

(一)修改标题栏显示文字的内容

1、修改AndroidManifest中< activity>的label属性

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.revise_12_1">

    <application
        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=".MainActivity2"></activity>
        <activity
            android:name=".MainActivity"
            android:label="this ok">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

(二)下拉刷新

在 Meterial Design 中,SwipeRefreshLayout 是用于实现下拉刷新的核心类,它由 support-v4 库提供,把要实现下拉刷新功能的控件放置到 SwipeRefreshLayout 中,就能让这个控件支持下拉刷新。

在内容外嵌套:

<android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
 
            <!--appbar_scrolling_view_behavior 唯一的作用是把自己(使用者)放到AppBarLayout的下面-->
            <android.support.v7.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
 
        </android.support.v4.widget.SwipeRefreshLayout>

上述代码值得注意的是,由于 RecyclerView 变成了 SwipeRefreshLayout 的子控件,因此之前用 app:layout_behavior 声明布局行为要移到 SwipeRefreshLayout 中才行。

修改活动:

// 下拉刷新
        swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
        swipeRefresh.setColorSchemeResources(R.color.colorPrimary);//设置刷新进度条颜色
        swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                // 处理刷新逻辑
                refreshPartner();
            }
        });

处理刷新逻辑(模拟)

/**
     * 下拉刷新数据(为简单起见没和网络交互)
     */
    private void refreshPartner() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        initPartner();//重新生成数据
                        adapter.notifyDataSetChanged();//通知数据变化
                        swipeRefresh.setRefreshing(false);//隐藏刷新进度条
                    }
                });
            }
        }).start();
    }

四.程序运行

1.虚拟机上运行结果

在这里插入图片描述

2.真实机上运行结果

在这里插入图片描述


总结

学完了本章的所有知识,你有没有觉得无比兴奋呢?反正我是这么觉得的。本章我们的收获实在是太多了,从一个什么都没有的空项目,经过一章的学习,最后实现了一个功能如此丰富、界面如此华丽的应用,还有什么事情比这个更让我们有成就感吗?
本章中我们充分利用了Design Support库、support-v4库、appcompat-v7库,以及一些开源项目来实现一个了高度Material化的应用程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值