Android音乐App桌面图标制作以及启动页面开发(简易音乐 一)

关于

其实一直想做一款属于自己的音乐app,然后给自己的好朋友用。但是因为种种原因和事情一直拖了好久没有付诸行动。前两天终于下定决心要在从新开发一个app。而且开发的过程也基本都会以专栏的形式记录下来,包括源码啥的。因为会很认真的坐下来,包括UI细节以及优化等等。
开发工具Android Studio 3.5
版本 Android androidx 9.0

效果

首先上一下启动页面以及桌面图标logo的gif:
在这里插入图片描述

第一步

关于桌面图标的实现,参考我的这篇文章 Android 实现App修改应用图标 。这里需要注意的一点是在最后一步,也就是这里选择circle,则显示的是圆形图标,选择square为正方形图标:
在这里插入图片描述

第二步

先看一下项目结构:
在这里插入图片描述
其中splashActivity是我们的启动页,PermissionHelper是我们的权限申请帮助类。

第一步 修改SplashAcitivity的布局页面

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:background="@color/red_trans"
    tools:context=".jy.personal.music.activity.SplashActivity">
    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:src="@drawable/launcher_back" />
         <!--图标资源会在博客最后放到网盘中-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_below="@+id/image"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/app_name"
        android:layout_marginTop="16dp"
        android:textStyle="bold"
        android:textSize="18sp"
        android:textColor="#2c2c2c"/>
</RelativeLayout>

第二步 修改androidmanifest.xml

添加要用到的部分权限(后面可能还会新增权限申请)

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <!--允许安装和卸载文件系统权限-->
    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" /> <!--申请电源锁权限-->
    <uses-permission android:name = "android.permission.DISABLE_KEYGUARD"/> <!--解锁屏幕需要的权限-->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!--全局对话弹出框,可能会有部分机型有问题,暂不考虑-->

修改splashactivity为启动页:

  <activity android:name=".jy.personal.music.activity.SplashActivity"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

第三步 权限申请帮助类

单独的权限申请方法如下:

 if (Build.VERSION.SDK_INT>22){
                    if (ContextCompat.checkSelfPermission(QueryPackingBarrelActivity.this,
                            android.Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED){
                        //先判断有没有权限 ,没有就在这里进行权限的申请
                        ActivityCompat.requestPermissions(QueryPackingBarrelActivity.this,
                                new String[]{android.Manifest.permission.CAMERA},991);

                    }else {
                        //说明已经获取到摄像头权限了 想干嘛干嘛
                       
                     
                    }
                }else {
//这个说明系统版本在6.0之下,不需要动态获取权限。
                    //说明已经获取到摄像头权限了 想干嘛干嘛
                 
                }
 /**
     * 高版本动态获取摄像头权限
     * @param requestCode 请求码
     * @param permissions 请求的权限
     * @param grantResults 返回的权限数据
     */
    @Override
    public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults) {
        switch (requestCode){
            case 991:
                if (grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
                    //这里已经获取到了摄像头的权限,想干嘛干嘛了可以
                 
                }else {
                    //这里是拒绝给APP摄像头权限,给个提示什么的说明一下都可以。
                    Toast.makeText(QueryPackingBarrelActivity.this,"请手动打开相机权限",Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }

    }

下面是封装的:

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.provider.Settings;

import android.util.Log;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

/**
 * Android 6.0 上权限分为<b>正常</b>和<b>危险</b>级别
 * <ul>
 * <li>正常级别权限:开发者仅仅需要在AndroidManifext.xml上声明,那么应用就会被允许拥有该权限,如:android.permission.INTERNET</li>
 * <li>危险级别权限:开发者需要在AndroidManifext.xml上声明,并且在运行时进行申请,而且用户允许了,应用才会被允许拥有该权限,如:android.permission.WRITE_EXTERNAL_STORAGE</li>
 * </ul>
 * 有米的以下权限需要在Android6.0上被允许,有米广告sdk才能正常工作,开发者需要在调用有米的任何代码之前,提前让用户允许权限
 * <ul>
 * <li>必须申请的权限
 * <ul>
 * <li>android.permission.READ_PHONE_STATE</li>
 * <li>android.permission.WRITE_EXTERNAL_STORAGE</li>
 * </ul>
 * </li>
 * <li>可选申请的权限
 * <ul>
 * <li>android.permission.ACCESS_FINE_LOCATION</li>
 * </ul>
 * </li>
 * </ul>
 * <p>Android 6.0 权限申请助手</p>
 * Created by Alian on 16-1-12.
 */
public class PermissionHelper {

	private static final String TAG = "PermissionHelper";

	/**
	 * 小tips:这里的int数值不能太大,否则不会弹出请求权限提示,测试的时候,改到1000就不会弹出请求了
	 */
	private final static int READ_PHONE_STATE_CODE = 101;

	private final static int WRITE_EXTERNAL_STORAGE_CODE = 102;

	private final static int REQUEST_OPEN_APPLICATION_SETTINGS_CODE = 12345;

	/**
	 * 有米 Android SDK 所需要向用户申请的权限列表
	 */
	private PermissionModel[] mPermissionModels = new PermissionModel[] {
			new PermissionModel("电话", Manifest.permission.READ_PHONE_STATE, "我们需要读取手机信息的权限来标识您的身份", READ_PHONE_STATE_CODE),
			new PermissionModel("存储空间", Manifest.permission.WRITE_EXTERNAL_STORAGE, "我们需要您允许我们读写你的存储卡,以方便我们临时保存一些数据",
					WRITE_EXTERNAL_STORAGE_CODE)
	};

	private Activity mActivity;

	private OnApplyPermissionListener mOnApplyPermissionListener;

	public PermissionHelper(Activity activity) {
		mActivity = activity;
	}

	public void setOnApplyPermissionListener(OnApplyPermissionListener onApplyPermissionListener) {
		mOnApplyPermissionListener = onApplyPermissionListener;
	}

	/**
	 * 这里我们演示如何在Android 6.0+上运行时申请权限
	 */
	public void applyPermissions() {
		try {
			for (final PermissionModel model : mPermissionModels) {
				if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(mActivity, model.permission)) {
					ActivityCompat.requestPermissions(mActivity, new String[] { model.permission }, model.requestCode);
					return;
				}
			}
			if (mOnApplyPermissionListener != null) {
				mOnApplyPermissionListener.onAfterApplyAllPermission();
			}
		} catch (Throwable e) {
			Log.e(TAG, "", e);
		}
	}

	/**
	 * 对应Activity的 {@code onRequestPermissionsResult(...)} 方法
	 *
	 * @param requestCode
	 * @param permissions
	 * @param grantResults
	 */
	public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
		switch (requestCode) {
		case READ_PHONE_STATE_CODE:
		case WRITE_EXTERNAL_STORAGE_CODE:
			// 如果用户不允许,我们视情况发起二次请求或者引导用户到应用页面手动打开
			if (PackageManager.PERMISSION_GRANTED != grantResults[0]) {

				// 二次请求,表现为:以前请求过这个权限,但是用户拒接了
				// 在二次请求的时候,会有一个“不再提示的”checkbox
				// 因此这里需要给用户解释一下我们为什么需要这个权限,否则用户可能会永久不在激活这个申请
				// 方便用户理解我们为什么需要这个权限
				if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, permissions[0])) {
					AlertDialog.Builder builder =
							new AlertDialog.Builder(mActivity).setTitle("权限申请").setMessage(findPermissionExplain(permissions[0]))
									.setPositiveButton("确定", new DialogInterface.OnClickListener() {

										@Override
										public void onClick(DialogInterface dialog, int which) {
											applyPermissions();
										}
									});
					builder.setCancelable(false);
					builder.show();
				}
				// 到这里就表示已经是第3+次请求,而且此时用户已经永久拒绝了,这个时候,我们引导用户到应用权限页面,让用户自己手动打开
				else {
					AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setTitle("权限申请")
							.setMessage("请在打开的窗口的权限中开启" + findPermissionName(permissions[0]) + "权限,以正常使用本应用")
							.setPositiveButton("去设置", new DialogInterface.OnClickListener() {

								@Override
								public void onClick(DialogInterface dialog, int which) {
									openApplicationSettings(REQUEST_OPEN_APPLICATION_SETTINGS_CODE);
								}
							}).setNegativeButton("取消", new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									mActivity.finish();
								}
							});
					builder.setCancelable(false);
					builder.show();
				}
				return;
			}

			// 到这里就表示用户允许了本次请求,我们继续检查是否还有待申请的权限没有申请
			if (isAllRequestedPermissionGranted()) {
				if (mOnApplyPermissionListener != null) {
					mOnApplyPermissionListener.onAfterApplyAllPermission();
				}
			} else {
				applyPermissions();
			}
			break;
		}
	}

	/**
	 * 对应Activity的 {@code onActivityResult(...)} 方法
	 *
	 * @param requestCode
	 * @param resultCode
	 * @param data
	 */
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		switch (requestCode) {
		case REQUEST_OPEN_APPLICATION_SETTINGS_CODE:
			if (isAllRequestedPermissionGranted()) {
				if (mOnApplyPermissionListener != null) {
					mOnApplyPermissionListener.onAfterApplyAllPermission();
				}
			} else {
				mActivity.finish();
			}
			break;
		}
	}

	/**
	 * 判断是否所有的权限都被授权了
	 *
	 * @return
	 */
	public boolean isAllRequestedPermissionGranted() {
		for (PermissionModel model : mPermissionModels) {
			if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(mActivity, model.permission)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 打开应用设置界面
	 *
	 * @param requestCode 请求码
	 *
	 * @return
	 */
	private boolean openApplicationSettings(int requestCode) {
		try {
			Intent intent =
					new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + mActivity.getPackageName()));
			intent.addCategory(Intent.CATEGORY_DEFAULT);

			// Android L 之后Activity的启动模式发生了一些变化
			// 如果用了下面的 Intent.FLAG_ACTIVITY_NEW_TASK ,并且是 startActivityForResult
			// 那么会在打开新的activity的时候就会立即回调 onActivityResult
			// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			mActivity.startActivityForResult(intent, requestCode);
			return true;
		} catch (Throwable e) {
			Log.e(TAG, "", e);
		}
		return false;
	}

	/**
	 * 查找申请权限的解释短语
	 *
	 * @param permission 权限
	 *
	 * @return
	 */
	private String findPermissionExplain(String permission) {
		if (mPermissionModels != null) {
			for (PermissionModel model : mPermissionModels) {
				if (model != null && model.permission != null && model.permission.equals(permission)) {
					return model.explain;
				}
			}
		}
		return null;
	}

	/**
	 * 查找申请权限的名称
	 *
	 * @param permission 权限
	 *
	 * @return
	 */
	private String findPermissionName(String permission) {
		if (mPermissionModels != null) {
			for (PermissionModel model : mPermissionModels) {
				if (model != null && model.permission != null && model.permission.equals(permission)) {
					return model.name;
				}
			}
		}
		return null;
	}

	private static class PermissionModel {

		/**
		 * 权限名称
		 */
		public String name;

		/**
		 * 请求的权限
		 */
		public String permission;

		/**
		 * 解析为什么请求这个权限
		 */
		public String explain;

		/**
		 * 请求代码
		 */
		public int requestCode;

		public PermissionModel(String name, String permission, String explain, int requestCode) {
			this.name = name;
			this.permission = permission;
			this.explain = explain;
			this.requestCode = requestCode;
		}
	}

	/**
	 * 权限申请事件监听
	 */
	public interface OnApplyPermissionListener {

		/**
		 * 申请所有权限之后的逻辑
		 */
		void onAfterApplyAllPermission();
	}
	
}

第四步 修改splashAcitivity.java

/**
 * 启动页
 * @version  V1.0.0
 * @author Tobey_R1
 * @since 2020年8月28日
 */
public class SplashActivity extends AppCompatActivity {

    private Context mContext;
    private PermissionHelper mPermissionHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //隐藏状态栏
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        //移除标题栏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_splash);
        //党系统版本6.0+,需要权限申请
        mPermissionHelper = new PermissionHelper(this);
        mPermissionHelper.setOnApplyPermissionListener(new PermissionHelper.OnApplyPermissionListener() {
            @Override
            public void onAfterApplyAllPermission() {
                runApp();
            }
        });
        if (Build.VERSION.SDK_INT<23){
            runApp();
        }else {
            //如果权限全部申请了,直接运行
            if (mPermissionHelper.isAllRequestedPermissionGranted()){
                runApp();
            }else {
                //如果还有权限未申请,且版本大于23,执行申请权限逻辑
                mPermissionHelper.applyPermissions();
            }
        }
    }
    /**
     * 高版本动态获取权限
     * @param  requestCode 请求码
     * @param  permissions 请求的权限
     * @param  grantResults 返回的权限数据
    * */
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        mPermissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        mPermissionHelper.onActivityResult(requestCode, resultCode, data);
    }
    private void runApp() {
        //设置开屏
        setupSplashAd();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    private void setupSplashAd() {
        //创建开屏容器  延迟显示2s
        Timer tmpTimer = new Timer();
        tmpTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                //根据有无缓存判断
                Intent intent = new Intent();
                intent.setClass(SplashActivity.this, MainActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION);
                startActivity(intent);

                overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
                finish();
                //这里finish();未添加的话在现有代码情况下运行测试会有bug。        
            }
        }, 2000);

    }
}

文章的最后放一下图标资源链接:
https://pan.baidu.com/s/1NXGB75ftAj4WSh3UUeD_yw 提取码 tobe。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪の星空朝酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值