我的编程空间,编程开发者的网络收藏夹
学习永远不晚

android 以音频播放器为例实现通知栏显示通知,并实现切歌、暂停、播放,并实现加载网络图片,并实现关闭第三方APP音频

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

android 以音频播放器为例实现通知栏显示通知,并实现切歌、暂停、播放,并实现加载网络图片,并实现关闭第三方APP音频

首先先给大家看下效果

接下来我们看下具体如何实施

1、首先我们创建一个音频的单例对象,这样能保证每次在播放的的音频是唯一的(类名如:MediaPlayerUtil.java)

package xxx;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.util.Log;
import xx.activity.couxrse.SoundPlayerActivity;
import xx.model.bo.AudioBo;
import java.util.List;

public class MediaPlayerUtil {
    private int index=0; // 记录音频重新被加载时上次选中的条目下标,对应集合的下标
    private String  path; // 对应集合下标index在数据中的音频
    private String title;
    private int duration; // 时长
    private List audioBoList;
    private MediaPlayer mPlayer;
    // 类初始化的时候立即加载该对象
    private static MediaPlayerUtil mediaPlayerInstance;
    // 私有化构造器
    public MediaPlayerUtil() {
    }
    // 提供该对象的获取方法(单例模式)
    public synchronized static MediaPlayerUtil getInstance() {
        if(mediaPlayerInstance == null)
        {
            mediaPlayerInstance = new MediaPlayerUtil();
        }
        return mediaPlayerInstance;
    }
    public int getIndex() {
        return index;
    }
    public void setIndex(int index) {
        this.index = index;
    }
    public String getPath() {
        return path;
    }
    public void setPath(String path) {
        this.path = path;
    }
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public int getDuration() { return duration; }
    public void setDuration(int duration) { this.duration = duration; }
    public List getAudioBoList() { return audioBoList; }
    public void setAudioBoList(List audioBoList) { this.audioBoList = audioBoList; }
    public MediaPlayer getmPlayer() { return mPlayer; }
    public void setmPlayer(MediaPlayer mPlayer) { this.mPlayer = mPlayer; }
    //播放方法
    public void play() {
        if(mPlayer!=null){
            mPlayer.stop();
            mPlayer.release(); // 释放相关的资源。
            mPlayer=null;
        }
        try {
            mPlayer = new MediaPlayer();
            // 设置指定的流媒体地址
            mPlayer.setDataSource(path);
            // 设置音频流的类型
            mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            
            mPlayer.prepare();
            mPlayer.start();
            mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    System.out.println(title+"播放完毕");
                    Log.d("tag", title+"播放完毕");
                    index=index+1;
                    path=audioBoList.get(index).getUrl();
                    title=audioBoList.get(index).getTitle();
                    System.out.println("准备播放"+title);
                    Log.d("tag", "准备播放"+title);
                    play();
                    //根据需要添加自己的代码。。。
                    if(NotifityActivity.getInstace()!=null){
                        NotifityActivity.getInstace().updateUI();
                     }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void replay(String path){
        if (mPlayer != null && mPlayer.isPlaying()) {
            mPlayer.seekTo(0);
            return;
        }
        play();
    }
    //暂停
    public void pause() {
        mPlayer.pause();
    }
    //判断是否正在播放中
    public boolean isplay() {
        return mPlayer.isPlaying();
    }
    //获取播放时长
    public long getduring() {
        // TODO Auto-generated method stub
        return mPlayer.getDuration();
    }
    //停止
    public void stop() {
        if(mPlayer!=null){
            mPlayer.stop();
        }
    }
    public void setPosition (int position) {
        mPlayer.seekTo(position);//重新设定播放进度
    }
    
    public void closeMedia() {
        if (mPlayer != null ) {
            mPlayer.stop();
            mPlayer.release(); // 释放相关的资源。
            mPlayer=null;
        }
    }
}

2、音频实体类

    private Long id;
    private String catalog; // 类别
    private String title; // 标题
    private int count; // 播放次数
    private int duration; // 时长
    private String publishTime; // 发布时间
    private String url; //  地址
    private String createTime; // 创建时间
    private String updateTime; //  更新时间
    private  int delFlag;//  是否删除
    private String imgUrl; // 相对应的背景图路径

 3、添加一个service服务类,增加音频后台播放功能

package xx.activity.course.audio;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class MediaService extends Service {
    public class MusicController extends Binder {
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return new MusicController();
    }
    @Override
    public void onCreate() {
        super.onCreate();
    }
    
    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }
}

4、在AndroidManifest.xml 加入以下代码

  

5、创建广播类(BroadcastReceiver) 实现对通知栏点击事件的实现以及回调(静态注册)

package xx.activity.course.audio;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.MediaPlayer;
import android.widget.Toast;
import xx.activity.course.SoundPlayerActivity;
import xx.fragment.classroom.holder.HomeAudioHolder;
import xx.media.MediaPlayerUtil;

public class NotificationClickReceiver extends BroadcastReceiver   {
    public static final String TYPE = "type"; //这个type是为了Notification更新信息的
    private MediaPlayerUtil mediaPlayerUtil;
    private MediaPlayer mediaPlayer;
    private int postion;
    private int endIndex;
    private Context context;
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        this.context = context;
        mediaPlayerUtil = MediaPlayerUtil.getInstance();
        endIndex = mediaPlayerUtil.getAudioBoList().size() - 1;
        int type = intent.getIntExtra(TYPE, -1);
        if (type != -1) {
            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.cancel(type);
        }
        if (action.equals("stop")) {
            //处理停止或播放点击事件
            mediaPlayerUtil = MediaPlayerUtil.getInstance();
            if (mediaPlayerUtil.getmPlayer()!=null && mediaPlayerUtil.isplay()) {
                mediaPlayerUtil.stop();
            } else {
                mediaPlayerUtil.setPath(mediaPlayerUtil.getAudioBoList().get(mediaPlayerUtil.getIndex()).getUrl());
                mediaPlayerUtil.play();
            }
        }
        if (action.equals("next")) {
            mediaPlayerUtil.stop();
            mediaPlayerUtil = MediaPlayerUtil.getInstance();
            int index = mediaPlayerUtil.getIndex();
            if ((index + 1) > endIndex) {
                Toast.makeText(context, "已经是最后一首了", Toast.LENGTH_SHORT).show();
                return;
            }
            postion = index + 1;
            mediaPlayerUtil.setIndex(postion);
            mediaPlayerUtil.setPath(mediaPlayerUtil.getAudioBoList().get(postion).getUrl());
            mediaPlayerUtil.setTitle(mediaPlayerUtil.getAudioBoList().get(postion).getTitle());
            mediaPlayerUtil.play();
        }
        if (action.equals("last")) {
            mediaPlayerUtil.stop();
            mediaPlayerUtil = MediaPlayerUtil.getInstance();
            //处理上一首
            int index = mediaPlayerUtil.getIndex();
            if ((index - 1) < 0) {
                Toast.makeText(context, "已经是第一首了", Toast.LENGTH_SHORT).show();
                return;
            }
            postion = index - 1;
            mediaPlayerUtil.setIndex(postion);
            mediaPlayerUtil.setPath(mediaPlayerUtil.getAudioBoList().get(postion).getUrl());
            mediaPlayerUtil.setTitle(mediaPlayerUtil.getAudioBoList().get(postion).getTitle());
            mediaPlayerUtil.play();
        }
        // 关闭通知栏
        if (action.equals("notification_cancelled")) {
            NotifityActivity.getInstace().closeNotifi();
            return;
        }
        // 更新音频页通知栏
        if (NotifityActivity.getInstace() != null) {
            NotifityActivity.getInstace().updateUI();
        }
    }
}

5、在AndroidManifest.xml 加入以下代码


        

 6、创建通知栏远程视图(RemoteViews)


        
 
            <!--
            -->
                
                        />
                
                

7、对应的activity中的设置

package com.lidou.quke.activity.course.audio;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.view.View;
import android.widget.Button;
import android.widget.RemoteViews;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.NotificationTarget;
import com.xx.R;
import xx.activity.BusinessActivity;
import com.xx.media.MediaPlayerUtil;
import com.xx.model.bo.AudioBo;
import java.util.ArrayList;
import java.util.List;

public class NotifityActivity extends BusinessActivity implements ServiceConnection {
    private static final int SDK_PAY_FLAG = 1;
    private final static String TAG = "加载SoundPlayerActivity类";
    private Button mbutton;
    private MediaPlayer mPlayer;
    // 这里如果不设置为-1 的话,默认是0,会造成进入列表第一条数据就显示为播放状态
    private int thisPosition;
    String channelId = "音频会话";//渠道id
    private MediaPlayerUtil mediaPlayerUtil;
    private Notification notification;
    private RemoteViews contentView;
    private NotificationTarget   notificationTarget;
    private AudioManager mAudioManager;
    //  检索了NotifityActivity的运行实例,以方便广播接收成功时处理activity相对应的逻辑处理(如:更新UI)
    private static NotifityActivity notifityActivity;
    public static NotifityActivity getInstace() {
        return notifityActivity;
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        notifityActivity = this;
        setContentView(R.layout.acs);
        Intent intent = new Intent(this, MediaService.class);
        //增加StartService,来增加后台播放功能
        startService(intent);
        bindService(intent, this, BIND_AUTO_CREATE);
        // 这里只是用来做测试数据
        List audioBoList=new ArrayList();
        AudioBo audioBo=new AudioBo();
        int a1 = 0;long b1 = (int)a1;
        audioBo.setId(b1);
        audioBo.setTitle("音频1");
        audioBo.setUrl("音频路径地址");
        audioBo.setImgUrl("网络图片地址");
        audioBoList.add(audioBo);
        AudioBo audioBo2=new AudioBo();
        int a = 1;long b = (int)a;
        audioBo2.setId(b);
        audioBo2.setTitle("音频2");
        audioBo2.setUrl("音频路径地址");
        audioBo2.setImgUrl("网络图片地址");
        audioBoList.add(audioBo2);
        mediaPlayerUtil=MediaPlayerUtil.getInstance();
        mediaPlayerUtil.setAudioBoList(audioBoList);
        initView();
    }
    private void initView() {
        // 我这里是在一个页面中的button事件唤起通知栏
        mbutton=findViewById(R.id.notifyButton);
        mbutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mediaPlayerUtil=MediaPlayerUtil.getInstance();
                // 调用通知栏加载方法
                initNotificationBar(); 
                // 1.上下文 2.图标控件的ResID 2.RemoteView  ,4 Notification 5 Notification_ID
                notificationTarget = new NotificationTarget(mContext, R.id.bgmmMusicImageView, contentView, notification, R.string.app_name);
                Glide.with(mContext).asBitmap().load(mediaPlayerUtil.getAudioBoList().get(0).getImgUrl())
                        .placeholder(R.drawable.test).into(notificationTarget);
            }
        });
        //1 初始化AudioManager对象
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        //2 申请焦点(关闭其它音频通道)
        mAudioManager.requestAudioFocus(mAudioFocusChange, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        mediaPlayerUtil = MediaPlayerUtil.getInstance();
        if (mediaPlayerUtil != null) {
            thisPosition = mediaPlayerUtil.getIndex();
        }
    }
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {
    }
    
    private void initRemoteView() {
        contentView = new RemoteViews(getPackageName(), R.layout.audio_music_notifi);// 远程视图
        mediaPlayerUtil = MediaPlayerUtil.getInstance();
        contentView.setTextViewText(R.id.musicTitleTextView, mediaPlayerUtil.getAudioBoList().get(mediaPlayerUtil.getIndex()).getTitle());
        contentView.setImageViewResource(R.id.audio_close_btn, R.drawable.player_icon_close);
        contentView.setImageViewResource(R.id.lastImageView, R.drawable.player_icon_last);
        contentView.setImageViewResource(R.id.nextImageView, R.drawable.player_icon_next);
        contentView.setImageViewResource(R.id.stopImageView, R.drawable.player_icon_stop);
        if (mediaPlayerUtil.getmPlayer()!=null && mediaPlayerUtil.isplay()) {
            contentView.setImageViewResource(R.id.stopImageView, R.drawable.player_icon_plays);
        } else {
            contentView.setImageViewResource(R.id.stopImageView, R.drawable.player_icon_stop);
        }
        // 实现停止/播放
        Intent intentStop = new Intent("stop");
        PendingIntent pIntentStop = PendingIntent.getBroadcast(this, 0, intentStop, 0);
        contentView.setOnClickPendingIntent(R.id.stopImageView, pIntentStop);
        //下一首事件
        Intent intentNext = new Intent("next");//发送播放下一曲的通知
        PendingIntent pIntentNext = PendingIntent.getBroadcast(this, 0, intentNext, 0);
        contentView.setOnClickPendingIntent(R.id.nextImageView, pIntentNext);
        //上一首事件
        Intent intentLast = new Intent("last");//发送播放上一曲的通知
        PendingIntent pIntentLast = PendingIntent.getBroadcast(this, 0, intentLast, 0);
        contentView.setOnClickPendingIntent(R.id.lastImageView, pIntentLast);
        // 关闭通知栏
        Intent intentCancelled = new Intent("notification_cancelled");
        PendingIntent pIntentCancelled = PendingIntent.getBroadcast(this, 0, intentCancelled, 0);
        contentView.setOnClickPendingIntent(R.id.audio_close_btn, pIntentCancelled);
    }
    
    private void initNotificationBar() {
        initRemoteView();
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        notification=new Notification();
        Intent intent = new Intent(mContext, NotificationClickReceiver.class); // 创建一个跳转到活动页面的意图
        PendingIntent pendingIntent = PendingIntent.getActivity(NotifityActivity.this, R.string.app_name, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        Notification.Builder builder = null; // 创建一个通知消息的构造器
        //  判断是否是android 8以上的版本,因为从8.0版本后唤起通知栏必须要填写渠道id和渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String description = "有趣,有用,有未来";
            int importance = NotificationManager.IMPORTANCE_LOW;//重要性级别
            // getPackageName() 获取APP渠道名称
            NotificationChannel mChannel = new NotificationChannel(channelId, "音频", importance);
            mChannel.setDescription(description);//渠道描述
            manager.createNotificationChannel(mChannel);//创建通知渠道
            mChannel.setSound(null,null);
            builder = new Notification.Builder(this, channelId);
            builder.setContentIntent(pendingIntent)
                    .setCustomContentView(contentView)
                    .setCustomBigContentView(contentView)
                    .setShowWhen(false)
                    .setSmallIcon(R.drawable.notification_icon) // 必填
                    .build();
            notification = builder.build();
        }else{ // 这里要兼顾android 8以下的版本
            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext,channelId);
            notificationBuilder.setCustomBigContentView(contentView)
                    .setCustomContentView(contentView)
                    .setContentIntent(pendingIntent)
                    .setSmallIcon(R.drawable.notification_icon)
                    .build();
            notification = notificationBuilder.build();
        }
        notification.flags = notification.FLAG_NO_CLEAR;//设置通知点击或滑动时不被清除*/
        manager.notify(R.string.app_name, notification);
    }
    
    public static synchronized String getPackageName(Context context) {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(
                    context.getPackageName(), 0);
            return packageInfo.packageName;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    @Override
    protected void onDestroy() {
        unbindService(this);
        super.onDestroy();
    }
    // 调用广播回调来更新activity中相关事件
    public void updateUI() {
        NotifityActivity.this.runOnUiThread(new Runnable() {
            public void run() {
                initView();
                initNotificationBar();
                mediaPlayerUtil = MediaPlayerUtil.getInstance();
                boolean isdestory;
                if (mActivity== null || mActivity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && mActivity.isDestroyed())) {
                    isdestory=true;
                } else {
                    isdestory=false;
                }
                // 由于图片使用Glide异步加载图片activity已销毁时时发生的崩溃
                if(isdestory==false){
                    // 此处为Glide的notificationTarget回调,当网络图片加载成功更新通知栏相对应控件的图像
                    notificationTarget = new NotificationTarget(mContext, R.id.bgmmMusicImageView, contentView, notification, R.string.app_name);
                    // 加载网络图片
                    Glide.with(mContext).asBitmap().load(mediaPlayerUtil.getAudioBoList().get(mediaPlayerUtil.getIndex()).getImgUrl()).placeholder(R.drawable.test).into(notificationTarget);
                }
                mAudioManager.abandonAudioFocus(mAudioFocusChange);
            }
        });
    }
    
    public void closeNotifi() {
        NotifityActivity.this.runOnUiThread(new Runnable() {
            public void run() {
                mediaPlayerUtil = MediaPlayerUtil.getInstance();
                mediaPlayerUtil.closeMedia();
                mAudioManager.abandonAudioFocus(mAudioFocusChange);
                NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                manager.cancel(R.string.app_name);
            }
        });
    }
    // 焦点监听
    AudioManager.OnAudioFocusChangeListener mAudioFocusChange = new AudioManager.OnAudioFocusChangeListener() {
        @Override
        public void onAudioFocusChange(int focusChange) {
            mediaPlayerUtil=MediaPlayerUtil.getInstance();
            if(focusChange==AudioManager.AUDIOFOCUS_LOSS) {
                //长时间丢失焦点,当其他应用如播放QQ音乐,网易云音乐播放时
                if (mediaPlayerUtil.isplay()) {
                    closeNotifi();
                }
                mAudioManager.abandonAudioFocus(mAudioFocusChange);
            }else if(focusChange== AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
                if (mediaPlayerUtil.isplay()) {
                    mediaPlayerUtil.stop();
                    updateUI();
                }
            }
        }
    };
}

再次捋下思路,

1、通知栏实现音频播放,主要使用到的是MediaPlayer播放器,

2、切歌我这里主要用到的是 静态广播来实现对通知栏点击事件的逻辑处理

3、加载网络图片主要用到的是Glide的NotificationTarget对象来及时更新相对应的图像,这里需要注意的是由于图片使用Glide异步加载图片,一定要在合适的地方去判断activity是否已销毁,不然会发生崩溃报错

4、在广播里触发不同的事件时,有时需要通知栏的图标或样式发生改变,那如何保证及时更新呢,我这里是在activity里创建一个它的实例,并写一个更新通知栏UI的方法,在广播需要用到的地方调用即可

5,说到音频就不得不说如何在播放自己项目的时候或接听电话、视频时关闭音频,或关闭第三方的音频了,这里主要要到的是AudioManager(音频管理器)

 至此一个完整的通知栏实现音频播放示例已完成,我也是第一次写,关于中间的service服务还不是很了解,代码还有很大的优化空间,具体到大家的项目中可根据需要灵活放入改变就好,如果您有更好的更简洁的方法,也欢迎分享,如果代码有哪里写的不好,更欢迎大家指正,


作者:。度


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

android 以音频播放器为例实现通知栏显示通知,并实现切歌、暂停、播放,并实现加载网络图片,并实现关闭第三方APP音频

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

android 以音频播放器为例实现通知栏显示通知,并实现切歌、暂停、播放,并实现加载网络图片,并实现关闭第三方APP音频

首先先给大家看下效果接下来我们看下具体如何实施 1、首先我们创建一个音频的单例对象,这样能保证每次在播放的的音频是唯一的(类名如:MediaPlayerUtil.java) package xxx; import android.media
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录