最近公司在做一个项目,有一个切换消息提示音的功能,可以切换本应用收到消息的提示音,而不影响系统提示音。我就按照微信的那个样式进行了编程,最终得到想要的效果。

转载请注明出处,谢谢:http://blog.csdn.net/harryweasley/article/details/46408037

怕有些人不知道怎么进入微信的新消息提示音功能,我这里说下操作步骤:

打开微信----我---设置---新消息提醒---新消息提示音。

经过以上的步骤就进入了这样的界面

这个是微信的效果图。

下面是我自己编程的效果图,如下图所示:

可以看到这两效果差别不是很大。

现在开始介绍一下具体实现的步骤。

本功能的最主要的功能是,这也是难点之一:获取到手机系统的提示音,并将它们显示在一个listview里面。

参考如下代码:

     // 获得RingtoneManager对象RingtoneManager manager = new RingtoneManager(this);// 设置RingtoneManager对象的类型为TYPE_NOTIFICATION,这样只会获取到notification的对应内容manager.setType(RingtoneManager.TYPE_NOTIFICATION);Cursor cursor = manager.getCursor();int num = cursor.getCount();Log.i("tag", num + "消息音个数");// 存储消息音名字的arrayListArrayList<String> ringtoneList = new ArrayList<String>();for (int i = 0; i < num; i++) {//获取当前i的铃声信息Ringtone ringtone = manager.getRingtone(i);//获取当前i的uri,设置notification的自定义铃声要用到Uri uri = manager.getRingtoneUri(i);//获取到当前铃声的名字String title = ringtone.getTitle(this);ringtoneList.add(title);}

将获取到的消息提示音的名字,加入到arrayList里。

先将主界面的信息贴上来,看一下,我再慢慢解释:

package jz.his.activity;import java.util.ArrayList;import jz.his.adapter.RingtoneAdapter;
import jz.his.jzhis.R;
import jz.his.util.SharedPreferenceUtil;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;public class RingtoneActivity extends Activity {ArrayList<String> ringtoneList;ListView listView;RingtoneManager manager;RingtoneAdapter adapter;String ringName = "";/*** 选择铃声的uri*/Uri uri = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_ringtone);listView = (ListView) findViewById(R.id.ringtone);getRingtone();// initRingtoneManager();// ringtoneList = FunctionActivity.ringtoneList;adapter = new RingtoneAdapter(this, ringtoneList, getIndex());listView.setAdapter(adapter);// 设置从第getIndex()行开始显示listView.setSelection(getIndex());listView.setOnItemClickListener(new OnItemClickListener() {@SuppressWarnings("static-access")@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {// 当点击的item是第一个“跟随系统”时if (position == 0) {// 得到系统默认的消息uriUri defalutUri = manager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);// 通过URI获得系统默认的Ringtone发出声音Ringtone defalutRingtone = manager.getRingtone(RingtoneActivity.this, defalutUri);defalutRingtone.play();ringName = "跟随系统";uri = null;} else {// 当点击的item不是第一个“跟随系统”时,获得的铃声要减一才对Ringtone ringtone = manager.getRingtone(position - 1);uri = manager.getRingtoneUri(position - 1);ringtone.play();ringName = ringtone.getTitle(RingtoneActivity.this);}adapter.first = new int[ringtoneList.size()];if (adapter.first[position] == 0) {adapter.first[position] = 1;} else {adapter.first[position] = 0;}adapter.notifyDataSetChanged();}});}/*** 初始化RingtoneManager对象,在listview的点击事件里面,用到了*/private void initRingtoneManager() {manager = new RingtoneManager(this);manager.setType(RingtoneManager.TYPE_NOTIFICATION);manager.getCursor();}/*** 得到当前铃声的行数*/private int getIndex() {for (int i = 0; i < ringtoneList.size(); i++) {if (SharedPreferenceUtil.getString(RingtoneActivity.this,SharedPreferenceUtil.RINGTONE_NAME).equals(ringtoneList.get(i))) {return i;}}return 0;}/*** 得到ringtone中的所有消息声音*/private void getRingtone() {manager = new RingtoneManager(this);manager.setType(RingtoneManager.TYPE_NOTIFICATION);Cursor cursor = manager.getCursor();int num = cursor.getCount();Log.i("tag", num + "消息音个数");ringtoneList = new ArrayList<String>();for (int i = -1; i < num; i++) {if (i == -1) {ringtoneList.add("跟随系统");} else {Ringtone ringtone = manager.getRingtone(i);// Uri uri = manager.getRingtoneUri(i);String title = ringtone.getTitle(this);ringtoneList.add(title);}}}public void allClick(View v) {switch (v.getId()) {case R.id.back_button:finish();break;case R.id.save:if (ringName == "") {// 没有改动铃声直接关闭界面finish();} else {// 已经改动uri,如果又选择了跟随系统,则uri为null,其他的就是uri本身if (uri == null) {SharedPreferenceUtil.setString(RingtoneActivity.this,SharedPreferenceUtil.url_string, "");} else {SharedPreferenceUtil.setString(RingtoneActivity.this,SharedPreferenceUtil.url_string, uri.toString());}Intent intent = new Intent();intent.putExtra("ringName", ringName);intent.setClass(RingtoneActivity.this, FunctionActivity.class);startActivity(intent);}default:break;}}
}

解释1.

因为listView显示的第一行是一个“追随系统”的item,所以我在适配数据的时候,有些小改变,在i=-1的时候,将ringtoneList添加为“追随系统”,其他的不变。因为进行了这样的处理,那么在点击各个item时候,获得铃声并进行播放时候,要做这样的处理:

Ringtone ringtone = manager.getRingtone(position - 1);

解释2.

最终将选择的铃声uri路径以String的格式存入到sharedPreference中。

在service里面进行设置,如下所示:主要看15--24行。

     NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);Notification n = new Notification();Intent intent = new Intent(this, FunctionActivity.class);intent.putExtra("messageData","messageData" );PendingIntent pi = PendingIntent.getActivity(this, 0, intent,PendingIntent.FLAG_ONE_SHOT);n.contentIntent = pi;// n.defaults = Notification.DEFAULT_ALL;if (SharedPreferenceUtil.getBoolean(this, SharedPreferenceUtil.IS_SOUND)) {} else {// 如果消息声音开启if (!SharedPreferenceUtil.getStringNull(OnlineService.this,SharedPreferenceUtil.url_string).equals("")) {// 如果选择了其他的系统声音n.sound = Uri.parse(SharedPreferenceUtil.getString(OnlineService.this, SharedPreferenceUtil.url_string));} else {// 默认的系统声音n.defaults |= Notification.DEFAULT_SOUND;}}if (SharedPreferenceUtil.getBoolean(this,SharedPreferenceUtil.IS_VIBRATE)) {} else {n.defaults |= Notification.DEFAULT_VIBRATE;}n.flags |= Notification.FLAG_SHOW_LIGHTS;n.flags |= Notification.FLAG_AUTO_CANCEL;// n.sound=Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6");n.icon = R.drawable.ic_launcher;n.when = System.currentTimeMillis();n.tickerText = tickerText;n.setLatestEventInfo(this, title, content, pi);notificationManager.notify(id, n);

注意:如果是要选择其他的声音,直接是n.sound = 其他声音的Uri

这个真的非常重要,就直接这样就可以了,看网上一大堆什么

notification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6"); //使用系统提供的铃音  

并不能有效果,我也不清楚为什么,如果大家有合理的解释,请告知,嘿嘿。

现在谷歌官方已经不推荐上面的那种notification的做法了,新的做法是下面的这个:

     Bitmap btm = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);// 这里大图标,小图标刚好相反NotificationCompat.Builder builder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_launcher).setContentTitle(title).setContentText(content).setTicker(tickerText);if (SharedPreferenceUtil.getBoolean(this, SharedPreferenceUtil.IS_SOUND)) {} else {// 如果消息声音开启if (!SharedPreferenceUtil.getStringNull(OnlineService.this,SharedPreferenceUtil.url_string).equals("")) {// 如果选择了其他的系统声音builder.setSound(Uri.parse(SharedPreferenceUtil.getString(OnlineService.this, SharedPreferenceUtil.url_string)));} else {// 默认的系统声音builder.setDefaults(Notification.DEFAULT_SOUND);}}if (SharedPreferenceUtil.getBoolean(this,SharedPreferenceUtil.IS_VIBRATE)) {} else {builder.setDefaults(Notification.DEFAULT_VIBRATE);}// 构建一个IntentIntent intent = new Intent(this, FunctionActivity.class);intent.putExtra("messageData","messageData" );sendData();// 封装一个IntentPendingIntent pendingIntent = PendingIntent.getActivity(this, 0,intent, PendingIntent.FLAG_ONE_SHOT);// 设置通知主题的意图builder.setContentIntent(pendingIntent);// 获取通知管理器对象NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);notificationManager.notify(id, builder.build());

关于这个新的notification的用法,你可以参看这个文章: http://blog.csdn.net/harryweasley/article/details/46348363

不过这个有个问题就是,builder.setDefaults()这个方法设置默认的铃声,闪关灯,震动,每次只能设置一次,不能多次调用这个方法来设置。如果有大神知道,请告知我。

解释3:

当点击保存按钮后,就进入到之前的界面,因为我之前的界面是一个viewpager+fragment的一个界面,一个activity里面加入了四个Fragment的这样的一个界面。进入到主activity时候,进行判断:

/*** 选择消息提示音后,跳转到功能界面后,直接将其跳转设置界面*/private void selectRingtone() {String ringName = getIntent().getStringExtra("ringName");Log.e("tag", ringName+"传过来的值");if (ringName != null) {pager.setCurrentItem(2);}}

直接跳转到第二个Fragment界面。如下图所示:

然后将设置界面的新消息提示音的内容进行改变:

     newSound = (TextView) getActivity().findViewById(R.id.new_sounde_text);newSound.setText(SharedPreferenceUtil.getStringSystem(getActivity(),SharedPreferenceUtil.RINGTONE_NAME));//第一次进入这个页面,下面的方法是不会执行的,因为ringName是nullString ringName = getActivity().getIntent().getStringExtra("ringName");if (ringName != null) {newSound.setText(ringName);Log.e("tag", ringName+"要保存的值");SharedPreferenceUtil.setString(getActivity(),SharedPreferenceUtil.RINGTONE_NAME, ringName);}

解释4:

你可能注意到,我在RingtoneActivity代码里注释了两行代码,你会发现,当我们每次进入这个RingtoneActivity的时候,都要重新加载数据到arrayList里面,虽然数据不是很多,但是肉眼可以感觉到是有点卡顿的,那么为了防止卡顿,我在进入RingtoneActivity之前的FunctionActivity页面开了一个子线程先加载数据到arrayList里面,定义成static类型。如下所示:

static ArrayList<String> ringtoneList;Runnable run = new Runnable() {@Overridepublic void run() {RingtoneManager manager = new RingtoneManager(FunctionActivity.this);manager.setType(RingtoneManager.TYPE_NOTIFICATION);Cursor cursor = manager.getCursor();int num = cursor.getCount();Log.i("tag", num + "消息音个数");ringtoneList = new ArrayList<String>();for (int i = -1; i < num; i++) {if (i == -1) {ringtoneList.add("跟随系统");} else {Ringtone ringtone = manager.getRingtone(i);// Uri uri = manager.getRingtoneUri(i);String title = ringtone.getTitle(FunctionActivity.this);ringtoneList.add(title);}}}};

这样在ringtoneActivity中,通过

ringtoneList = FunctionActivity.ringtoneList;

就获得了数据,这样就不会有卡顿了。 但是我这个方法用到了static定义变量,这样容易造成oom,具体参看 http://blog.csdn.net/harryweasley/article/details/45872685   android内存泄露优化总结

所以我弃用了这个方法,不知道有没有大神可以给个建议呢。

解释5:

当你选择了其他的铃声的时候,再次进入新消息提示音界面时候,是从当前选择的铃声开始展示的,如图所示:

当我选择了Clever这个铃声的时候,我再次进入这个页面,会从Clever这行开始显示。这个功能是这样实现的。嘿嘿,并没有想象的那么难吧,其实listview就自带这个方法的,只需要传入当前item的位置是第几个就行了。

// 设置从第getIndex()行开始显示listView.setSelection(getIndex());
/*** 得到当前铃声的行数*/private int getIndex() {for (int i = 0; i < ringtoneList.size(); i++) {if (SharedPreferenceUtil.getString(RingtoneActivity.this,SharedPreferenceUtil.RINGTONE_NAME).equals(ringtoneList.get(i))) {return i;}}return 0;}

RingtoneAdapter里的内容是这样的:

package jz.his.adapter;import java.util.ArrayList;import jz.his.adapter.MessageAdapter.ViewHolder;
import jz.his.jzhis.R;import android.content.Context;
import android.opengl.Visibility;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;public class RingtoneAdapter extends BaseAdapter {Context context;ArrayList<String> list;/*** 建立一个数组,默认都为0*/public int[] first;int index;public RingtoneAdapter(Context cont, ArrayList<String> arayList, int index) {context = cont;list = arayList;this.index = index;first = new int[list.size()];}class ViewHolder {TextView title;ImageView image;}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder = null;if (convertView == null) {holder = new ViewHolder();convertView = LayoutInflater.from(context).inflate(R.layout.item_ringtone, null);holder.title = (TextView) convertView.findViewById(R.id.title);holder.image = (ImageView) convertView.findViewById(R.id.image);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}holder.title.setText(list.get(position));if (first[position] == 0) {holder.image.setVisibility(View.GONE);} else {holder.image.setVisibility(View.VISIBLE);// 当点击其他item后,将index置为-1,则下面的if语句则不会再执行进入了index = -1;}// 第一次进来的时候,让当前item的图片可见if (position == index) {holder.image.setVisibility(View.VISIBLE);}return convertView;}}

RingtoneAdapter里进行了判断,是否某个item后面的对勾显示出来。这里当时还是纠结了一会的,最终还是解决了。特此记录。

item_ringtone布局的代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" ><TextViewandroid:id="@+id/text"android:layout_width="wrap_content"android:layout_height="5dp" /><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/text"android:layout_margin="5dp"android:gravity="center_vertical"android:text="mingzi"android:textSize="15sp" /><TextViewandroid:id="@+id/text2"android:layout_width="wrap_content"android:layout_height="5dp"android:layout_below="@id/title" /><ImageView android:id="@+id/image"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_margin="10dp"android:src="@drawable/umeng_socialize_oauth_check_on"android:visibility="gone" /></RelativeLayout>

里面的有两个空白的textView是为了扩开每个item的高度,为了让铃声名字看起来是在中间位置。

activity_ringtone下面的布局代码如下所示:

<?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" ><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="55dip"android:background="@color/balck"android:orientation="horizontal" ><LinearLayoutandroid:id="@+id/back_button"android:layout_width="wrap_content"android:layout_height="fill_parent"android:gravity="center_vertical"android:onClick="allClick" ><ImageViewandroid:layout_width="10dip"android:layout_height="18dip"android:layout_gravity="center"android:layout_marginLeft="15dip"android:layout_marginRight="10dip"android:src="@drawable/icon_left_arrow" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="新消息提示音"android:textColor="@color/white"android:textSize="20sp" /></LinearLayout><Buttonandroid:id="@+id/save"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:background="@drawable/account_backg"android:onClick="allClick"android:text="保存"android:textColor="@color/white" /></RelativeLayout><ListViewandroid:id="@+id/ringtone"android:layout_width="match_parent"android:layout_height="wrap_content"android:scrollbars="none" ></ListView></LinearLayout>

Button的account_backg代码是:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >  <!-- 内部颜色 -->  <solid android:color="@color/account_green" />  <!-- 边缘线条颜色 -->  <stroke  android:width="1dp"  android:color="@color/account_green" />  <!-- 圆角的幅度 -->  <corners  android:bottomLeftRadius="5dip"  android:bottomRightRadius="5dip"  android:topLeftRadius="5dip"  android:topRightRadius="5dip" />  </shape>  

这样基本的功能就写完了,因为是公司整个项目的,所以不能发源码给大家,但是有任何意见或者问题,可以在评论和我沟通,嘿嘿,共同进步嘛。

高仿微信新消息提示音功能相关推荐

  1. android微信加人有提示音吗,Android仿微信新消息提示音

    環信聊天消息提示音的實現 仿微信新消息提示音設置. 思路:用RingtoneManager查詢出title,Ringtone,uri信息,title用來展示,Ringtone用來播放,uri設置提示音 ...

  2. android接收消息后提示音,Android仿微信新消息提示音

    怕有些人不知道怎么进入微信的新消息提示音功能,我这里说下操作步骤: 打开微信----我---设置---新消息提醒---新消息提示音. 经过以上的步骤就进入了这样的界面 具体实现的步骤. 难点之一:获取 ...

  3. android新消息提醒功能,Android仿微信新消息提示音

    怕有些人不知道怎么进入微信的新消息提示音功能,我这里说下操作步骤: 打开微信----我---设置---新消息提醒---新消息提示音. 经过以上的步骤就进入了这样的界面 具体实现的步骤. 难点之一:获取 ...

  4. android 更换软件提示音,修改微信APP新消息提示音(教程)!

    熟悉我的朋友都知道,我只带来干货,每天都是实用技能!今天教大家如何自定义 消息通知铃声.来电铃声.闹铃铃声,Android操作系统由于其特征,自定义这些很简单,目前很多音乐APP软件都有个" ...

  5. android高仿微信聊天消息列表自由复制文字,双击查看文本内容

    SelectTextHelper-高仿微信聊天消息列表自由复制文字,双击查看文本内容 掘金地址 github地址 SelectTextHelper打造一个全网最逼近微信聊天消息自由复制,双击查看文本内 ...

  6. web页面 新消息提示音

    web页面 新消息提示音 链接:https://blog.csdn.net/fmyzc/article/details/83750141

  7. 工作篇 之 高仿微信双击消息弹出可自由复制

    LZ-Says:书山有路勤为径,学海无涯苦作舟. 前言 最近呐,难已琢磨. 很喜欢,却又很忧愁. 喜欢的是,找到了自己认可的.喜欢的工作: 忧愁的是,压力山大. I Love-! 举个栗子 Enmmm ...

  8. web页面 新消息提示音

    1.首先需要一个jq插件,将插件引入页面 下载地址     密码:ikkq 2.代码 html: <if condition="$tip eq true"><di ...

  9. android开发百度地图坐标偏差,利用百度地图Android sdk高仿微信发送位置功能及遇到的问题...

    接触了百度地图开发平台半个月了,这2天试着模仿了微信给好友发送位置功能,对百度地图的操作能力又上了一个台阶 我在实现这个功能的时候,遇到一些困难,可能也是别人将会遇到的困难,特在此列出 1.在微信发送 ...

最新文章

  1. Android之二维码生成与扫描
  2. 用 Flask 来写个轻博客 (32) — 使用 Flask-RESTful 来构建 RESTful API 之一
  3. SLB vs CLB
  4. 加密软件漏洞评测系统_调查:加密货币挖矿仍居恶意软件威胁前列
  5. 华为回应“锁屏广告”事件:非官方所为
  6. java用于保存登录对象怎么写,利用对象流模仿登陆注册功能——Java对象流应用...
  7. PHP:header()函数
  8. 动态填充html select tag的options
  9. 助创cms众筹 php,【教程】助创cms众筹系统完整测试流程详解
  10. Spring Boot项目能之前能正常跑,安装禅道后突然就不行了报错Unknown database “数据库名“
  11. 模仿qq空间或朋友圈发布动态、评论动态、回复评论、删除动态或评论的功能(下)(核心部分)...
  12. android网易云音乐api调用,网易云音乐常用API浅析 – Moonlib
  13. php 汽车品牌三级联动,车辆品牌型号的三级联动菜单怎么做的
  14. Caliburn.Micro WPF教程——创建项目
  15. ubuntu18.04 卸载Anaconda3
  16. poi操作ppt创建表格
  17. HCIP第十六天(VLAN IF接口,STP生成树协议,BPDU的配置)
  18. Docker 启动和退出一个容器
  19. 百度OCR java-SDK做图文识别
  20. Ecshop会员注册的Email 电子邮箱改成非必填项

热门文章

  1. Java 多个List合并
  2. Echarts的Category轴滑动
  3. Python isspace() 方法
  4. 自然语言处理学习——论文分享——A Mutual Information Maximization Perspective of Language Representation Learning
  5. 彻底理解Java并发:Java并发原子类
  6. C1任务03 Web的世界(下)
  7. 在Ubuntu调用opencv库编程显示图片并叠加文字
  8. Java全角半角的转换
  9. 使用mac笔记本基础技巧
  10. 【Cryo】裴蜀定理 二元一次方程的整数解