音乐播放器问题记录

记录几个碰到的感觉网上没有找到很好解决办法的问题。

一、通过ContentProvider数据集获取歌曲数据

获取数据时,我们需要在 m a n i f e s t manifest manifest文件中添加权限,如果按照第十章ppt上的方法使用 A c t i v i t y R e s u l t L a u n c h e r ActivityResultLauncher ActivityResultLauncher来获取歌曲,初始化你的 L i s t List List时,顺序会和写的顺序不一样。

举个例子

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mActivity = this;
    Log.d("myflag", "0");
    permissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
    Log.d("myflag", "2");
    Init_View();
    Init_RecyclerView();
}
private final ActivityResultLauncher permissionLauncher = registerForActivityResult(
        new ActivityResultContracts.RequestPermission(),
        new ActivityResultCallback<Boolean>() {
            @Override
            public void onActivityResult(Boolean result) {
                if (result) {
                    Log.d("myflag","1");
                    Load_Local_Music();
                }
            }
        }
);

先看这两个图,你可能会认为 L o g . d Log.d Log.d中数字输出的顺序是012,但是实际上输出的顺序是021。这是为什么呢?主观上我们可能把 L a u n c h e r Launcher Launcher当成一个普通的函数了,但实际上他会在 O n C r e a t e OnCreate OnCreate函数执行结束后这个回调函数才会被调用。这会导致什么问题呢?本来我们想的是先初始化了 L i s t List List后再去用这个 L i s t List List初始化 R e c y c l e r V i e w RecyclerView RecyclerView A d a p t e r Adapter Adapter,但是实际上我们在初始化 A d a p t e r Adapter Adapter L i s t List List并没有被初始化,就会出问题。

解决这个问题的办法有两个:

①把初始化 R e c y c l e r V i e w RecyclerView RecyclerView的部分也写到启动器的回调函数里

②把初始化 L i s t List List的函数不放在启动器的回调函数里,而是直接放在 o n C r e a t e onCreate onCreate里,但是这样要确保权限已经申请好了(提前在外面开好或者用一次launch让他弹出来给你点)

二、关于用来初始化 A d a p t e r Adapter Adapter L i s t List List

我们可以看到第十章的PPT里获取音乐列表的 L i s t List List是让 L i s t List List等于了 g e t M u s i c L i s t getMusicList getMusicList的返回值,这样得到的 L i s t List List是没问题的,有的人想这样让 L i s t List List等于之后调用 a d a p t e r . n o t i f y D a t a S e t C h a n g e d ( ) adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()之后 R e c y c l e r V i e w RecyclerView RecyclerView就正常了。很可惜,这样的想法是错误的。按我的理解, A d a p t e r Adapter Adapter里的 L i s t List List类似指针,还是指向原来的那个 L i s t List List,而你让主函数里的 L i s t List List直接等于另一个 L i s t List List的话,修改了指针,但是 A d a p t e r Adapter Adapter L i s t List List的指针并没有被修改。

如果上面理解不了的话,就记住 A d a p t e r Adapter Adapter初始化用的 L i s t List List在用来初始化 A d p a t e r Adpater Adpater之后就不要用 = = =来更改了,只能在原来的 L i s t List List的基础上增减。

解决方法:

①先初始化 L i s t List List,在初始化 A d a p t e r Adapter Adapter

②不用=来修改 L i s t List List,而是一个一个的 a d d add add,修改完后 n o t i f y n o t i f y D a t a S e t C h a n g e d ( ) notifynotifyDataSetChanged() notifynotifyDataSetChanged()一下

三、自定义 n o t i f i c a t i o n notification notification视图和点击事件

这部分网上讲的要么不清楚,要么版本和现在差太远了,所以在这里从头到尾讲一下。

我们先自定义一个 L i n e a r L a y o u t LinearLayout LinearLayout的视图,来作为我们填充到通知里的布局,需要注意的是布局的宽度不要超过256dp,否则通知栏里装不下,会显示不全。

视图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
请添加图片描述

他们的ID

然后我们需要用到一个新东西—— R e m o t e V i e w RemoteView RemoteView

直接用代码来演示好了

        remoteViews = new RemoteViews(getPackageName(),R.layout.notification_view);
        //                            当成默认格式就行         你刚刚自定义的视图

        //将图片绑定到视图里的ImageView上,第一个参数是控件的ID,第二个参数是你自己的图片
        remoteViews.setImageViewResource(R.id.not_previous, R.drawable.previous);
        remoteViews.setImageViewResource(R.id.not_play, R.drawable.play);
        remoteViews.setImageViewResource(R.id.not_pause, R.drawable.pause);
        remoteViews.setImageViewResource(R.id.not_next, R.drawable.next);

RemoteView中,如果你的 I m a g e V i e w ImageView ImageView没有绑定,那么它对应的位子显示的会是空白,而如果是 T e x t V i e w TextView TextView,他则会显示你在视图中写的东西。

接下来把他设置到 N o t i f i c a t i o n Notification Notification

        manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        channel = new NotificationChannel(
                "MyChannel",
                "Channel_Name",
                NotificationManager.IMPORTANCE_HIGH
        );
        manager.createNotificationChannel(channel);

        builder = new Notification.Builder(this, "MyChannel")
//                .setCustomContentView(remoteViews)
                .setCustomBigContentView(remoteViews)
//                .setCustomHeadsUpContentView(remoteViews)
                .setSmallIcon(R.drawable.twitter);
        notification = builder.build();
        manager.notify(123, notification);

只需要将 r e m o t e V i e w s remoteViews remoteViews设置到 b u i l d e r builder builder中,这里有三种设置方式:

①setCustomContentView 通知中布局高度固定为64dp,如果视图太大了会显示不全。

②setCustomBigContentView 可以将通知下拉,展开你的全部视图

③setCustomBigContentView 将小图标放到了最前面

可以把它们都试一次,就知道具体的效果会是什么了。

###builder中必须设置SmallIcon,否则通知将创建不成功,其他的图标可以不用管了,因为你有了自定义的布局。

接下来是重点

如何设置点击事件

这里用到的是 B r o a d C a s t BroadCast BroadCast来实现的

还是来看例子

Intent intent_previous = new Intent(this,NotificationClickReceiver.class);
//Intent intent_previous = new Intent();
intent_previous.setAction("previous");
PendingIntent pendingIntent_previous = PendingIntent.getBroadcast(this, 0, intent_previous, PendingIntent.FLAG_IMMUTABLE);
remoteViews.setOnClickPendingIntent(R.id.not_previous, pendingIntent_previous);

然后来讲解一下,这里我们先创建了一个从 t h i s this this N o t i f i c a t i o n C l i c k R e c e i v e r NotificationClickReceiver NotificationClickReceiver I n t e n t Intent Intent,然后我们给他设置了标识 A c t i o n Action Action,再用这个 I n t e n t Intent Intent创建了一个 P e n d i n g I n e t e n t PendingInetent PendingInetent,最后将这个 P e n d i n g I n t e n t PendingIntent PendingIntent r e m o t e V i e w s remoteViews remoteViews里的控件绑定起来。

###记得静态或者动态注册一下 B r o a d C a s t BroadCast BroadCast

*如何理解 P e n d i n g I n t e n t PendingIntent PendingIntent

P e n d i n g I n t e n t PendingIntent PendingIntent可以就看做是一个满足一定条件就执行的事件

它有三种创建方式:

①getActivity(Context context, int requestCode, Intent intent, int flags)

②getService(Context context, int requestCode, Intent intent, int flags)

③getBroadcast(Context context, int requestCode, Intent intent, int flags)

这三种方式可以看成被执行的事件,第一个就是满足了条件就跳转到一个 A c t i v i t y Activity Activity,第二个是启动一个 S e r v i c e Service Service,第三个是发送一个广播。

r e q u e s t C o d e requestCode requestCode可以随便填,这里不太用得到它, i n t e n t intent intent可以理解为起点和终点,看向上面的代码,第一行写的可以理解为起点是当前的地方,终点是 N o t i f i c a t i o n C l i c k R e c e i v e r NotificationClickReceiver NotificationClickReceiver,我们发的通知只有在这个receiver里才会被处理,而第二行注释掉的就没有这个限制,所有的 R e c e i v e r Receiver Receiver都可以收到他的广播。

f l a g s flags flags有六种值,感兴趣的可以去查一下,这里用的 P e n d i n g I n t e n t . F L A G — I M M U T A B L E PendingIntent.FLAG_—IMMUTABLE PendingIntent.FLAGIMMUTABLE标记构建无法被修改的 P e n d i n g I n t e n t PendingIntent PendingIntent,常用于由于明确知道未来需要进行的操作。这里如果使用的Flag错误会导致绑定出问题。

那么这里的一定条件是什么呢?答案是我们绑定到控件上的onClick。

最后我们在接收器中判断 a c t i o n action action,然后来写点击事件就完成了。

public class NotificationClickReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        MainActivity mainActivity=MainActivity.getInstace();
        String action = intent.getAction();
        if(action.equals("play")){
			*****
        }
        if(action.equals("pause")){
             *****
        }
        if(action.equals("next")){
			*****
        }
        if(action.equals("previous")){
			*****
        }
    }
}

最后建议各位去网上找关于 I n t e n t Intent Intent S e r v i c e Service Service B r o a d C a s t BroadCast BroadCast的内容看一下,那PPT上的东西属实是太少了。

T i p s Tips Tips

设置 R e c y c l e r V i e w RecyclerView RecyclerView各个 i t e m item item间距:链接

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值