摘要:本次实现了用户登录注册,将用户保存到Application 里面实现用户持久化,用户有已读消息查看,未读消息查看,发送消息功能,未读消息读取后,添加到已读消息里面,发送消息具有推送功能 可以全部发送,和选择人员发送,发送消息过后,如果当前用户在线会收到一条任务栏通知,点击通知可以查看到该消息,登录App时,APP应用会生成,未读信息角标,(实现了vivo和小米。
流程图:
项目结构
项目使用jar:
项目使用权限:
广播接收器:
<!-- Required SDK 核心功能 -->
<!-- 可配置android:process参数将PushService放在其他进程中 -->
<service
android:name="cn.jpush.android.service.PushService"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="cn.jpush.android.intent.REGISTER" />
<action android:name="cn.jpush.android.intent.REPORT" />
<action android:name="cn.jpush.android.intent.PushService" />
<action android:name="cn.jpush.android.intent.PUSH_TIME" />
</intent-filter>
</service>
<!-- since 1.8.0 option 可选项。用于同一设备中不同应用的JPush服务相互拉起的功能。 -->
<!-- 若不启用该功能可删除该组件,将不拉起其他应用也不能被其他应用拉起 -->
<service
android:name="cn.jpush.android.service.DaemonService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="cn.jpush.android.intent.DaemonService" />
<category android:name="com.example.pk.tuisong" />
</intent-filter>
</service>
<!-- Required SDK核心功能 -->
<receiver
android:name="cn.jpush.android.service.PushReceiver"
android:enabled="true">
<intent-filter android:priority="1000">
<action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED_PROXY" />
<category android:name="com.example.pk.tuisong" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
<!-- Optional -->
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<!-- Required SDK核心功能 -->
<activity
android:name="cn.jpush.android.ui.PushActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:theme="@android:style/Theme.NoTitleBar">
<intent-filter>
<action android:name="cn.jpush.android.ui.PushActivity" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.pk.tuisong" />
</intent-filter>
</activity>
<!-- SDK核心功能 -->
<activity
android:name="cn.jpush.android.ui.PopWinActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:theme="@style/MyDialogStyle">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.pk.tuisong" />
</intent-filter>
</activity>
<!-- Required SDK核心功能 -->
<service
android:name="cn.jpush.android.service.DownloadService"
android:enabled="true"
android:exported="false" />
<!-- Required SDK核心功能 -->
<receiver android:name="cn.jpush.android.service.AlarmReceiver" />
数据表结构:
User表:
字段 | 类型 | 作用 | 备注 |
ID | Int | 主键,自增长 | 确定每条数据的唯一性 |
Username | String | 用户名,唯一 | 极光推送的别名 |
Password | String | 密码 |
|
Xiaoxi表:
字段 | 类型 | 作用 | 备注 |
ID | Int | 主键 | 确定每条数据的唯一性 |
Username | String | 用户名 | 确定是哪个用户的消息 |
Xiaoxi | String | 消息,内容 | 该条消息的内容 |
Biaoti | String | 消息的标题 | 本条消息的标题 |
第一步:
实现登录注册,把账号信息发送给服务器,绑定用户,以便后面消息传送操作!
(此功能上次已做!)
第二步:
消息的传送:
进入该activity时 通过服务器查询出该用户的 已读消息 和未读消息,
点击已读消息时 会跳转到一个listview 里面显示了该用户的已读消息,
点击未读消息的时候 会跳转到一个listview 里面显示了该用户的未读消息,改listview 拥有一个点击事件,当点击某条消息时,会跳转到一个显示页面,显示该条信息,并把该消息的状态改为已读。
Listview的点击事件:
ListView list = (ListView) findViewById(R.id.listwd);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
text=(TextView)arg1.findViewById(R.id.friend_username);
String name1 = text.getText().toString();
int aid =text.getId();
Toast.makeText(Unread.this,"ID" + arg2 + "个项目",Toast.LENGTH_SHORT).show();
xiaoxics.setUsername(name);
xiaoxics.setBiaoti(name1);
xiaoxics.setXiaoxizt(arg2+"");
String xiaoxijson = JSON.toJSONString(xiaoxics);
Intent intent = new Intent(Unread.this,XianshiXinXi.class);
intent.putExtra("shuju",xiaoxijson);
startActivity(intent);
}
});
此处实现了listview里面 拥有一个简单的Textview的点击事件,请勿假如Button,加入Button 此点击事件将无效!
点击发送消息时,会跳到一个全新的activity
在这里 输入消息的标题和内容 点击发送所有人时 会把次消息发送给服务器 服务器保存该消息,并像用户推送
public staticString push(List<String> username,Stringbiaoti,String username1){
user = new User();
user.setUsername(username1);
user.setPassword(biaoti);
userjson = JSON.toJSONString(user);
fhz = "loser";
masterSecret ="cb79148f2b69efa00dbc16b0";
appKey = "76a005b037fa2b8194fe412a";
jpushClient =new JPushClient(masterSecret,appKey);
payload =PushPayload.newBuilder()
.setMessage(Message.content(userjson))
.setPlatform(Platform.android_ios())
.setAudience(Audience.alias(username))
.setNotification(Notification.newBuilder()
.addPlatformNotification(AndroidNotification.newBuilder()
"type","传回去的数据)
"你有一条新消息")
.build())
.addPlatformNotification(IosNotification.newBuilder()
"type","传回去的数据")
"你有一条新消息")
.build())
.build())
.setOptions(Options.newBuilder()
.setApnsProduction(false)
/
.build())
.build();
点击发送对象时 会把该页面的主题 和内容传到一个新的页面,该页面有一个listview ,该listview 显示了所有的用户名,具有一个多选事件,当选择完用户后,会把主题和内容和用户集合发送给服务器,服务器会根据用户名推送消息。
public class SendOut extends BaseActivity {
ListView list;
List<User> userList,usernamelist = null;
Fsong fsong = null;
MyHandiler2 myHandiler2;
ArrayList<HashMap<String, Object>> listData;
//适配器
CheckboxAdapter listItemAdapter;
String name1=null;
TextView buttonfsdxfhsy;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_send_out);
buttonfsdxfhsy = (TextView) findViewById(R.id.buttonfsdxfhsy);
myHandiler2 = new MyHandiler2();
Intent intent = getIntent();
String fsongjson = intent.getStringExtra("fsong");
fsong = JSON.parseObject(fsongjson, Fsong.class);
//反回主页
buttonfsdxfhsy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent23 = new Intent(SendOut.this,Home_page.class);
intent23.putExtra("dxfsfh",fsong.getUsername());
startActivity(intent23);
}
});
Button getValue = (Button) findViewById(R.id.get_value);
getValue.setOnClickListener(listener);
//listview
list = (ListView) findViewById(R.id.list);
//存储数据的数组列表
listData = new ArrayList<HashMap<String, Object>>();
//显示所有已读消息
final okHttp ok = new okHttp();
try {
new Thread(new Runnable() {
@Override
public void run() {
Message msg = new Message();
try {
userList = ok.duxianzs();
msg.what = 1;
String listjson = JSON.toJSONString(userList);
Bundle bundle = new Bundle();
bundle.putSerializable("list", listjson);
msg.setData(bundle);
} catch (Exception e) {
e.printStackTrace();
}
myHandiler2.sendMessage(msg);
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
//事件响应
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
HashMap<Integer, Boolean> state = listItemAdapter.state;
List<User> stringlist =new ArrayList<User>();
String options = "选择的项是:";
for (int j = 0; j < listItemAdapter.getCount(); j++) {
System.out.println("state.get(" + j + ")==" + state.get(j));
if (state.get(j) != null) {
User user = new User();
@SuppressWarnings("unchecked")
HashMap<String, Object> map = (HashMap<String, Object>) listItemAdapter.getItem(j);
String username = map.get("friend_username").toString();
user.setUsername(username);
Log.i("info", "__________________________9527___________________" +username);
options+="\n"+"."+username;
Log.i("info", "__________________________9527___________________" +options);
stringlist.add(user);
}
}
fsong.setUserList(stringlist);
Log.i("info", "__________________________9527___________________" +fsong.getXiaoxi());
final okHttp ok = new okHttp();
try {
new Thread(new Runnable() {
@Override
public void run() {
Message msg = new Message();
try {
String xiaoxi = ok.dxtssj(fsong);
msg.what = 2;
Bundle bundle = new Bundle();
bundle.putSerializable("xiaoxixi", xiaoxi);
Log.i("info", "____________9527______________9527___________________" +xiaoxi);
msg.setData(bundle);
} catch (Exception e) {
e.printStackTrace();
}
myHandiler2.sendMessage(msg);
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
};
//数据的传递
public class MyHandiler2 extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
String list12 = (String) msg.getData().getSerializable("list");
List<User> userlistqw =JSON.parseArray(list12, User.class);
Log.i("info","____________________________________________________________"+userList.size());
for(int i=0;i<userList.size();i++){
HashMap<String, Object> map=new HashMap<String, Object>();
map.put("friend_username",userList.get(i).getUsername());
map.put("selected", false);
//添加数据
listData.add(map);
}
//适配器
listItemAdapter = new CheckboxAdapter(SendOut.this, listData);
list.setAdapter(listItemAdapter);
break;
case 2:
String xiaoxixi = (String) msg.getData().getSerializable("xiaoxixi");
Log.i("info","_______________________888____888____888_____________________________"+xiaoxixi);
String name =xiaoxixi.substring(0,1);
if (name.equals("1")) {
Toast.makeText(getApplicationContext(), "发送成功!", Toast.LENGTH_LONG).show();
} else {
//显示选择内容
Toast.makeText(getApplicationContext(), "发送失败!", Toast.LENGTH_LONG).show();
}
break;
}
}
}
第三步:
对接收推送回来的数据进行操作:
推送回来的消息会被BroadcastReceiver广播接收,在此广播中队接到的数据进行操作!
public class MyReceiver extends BroadcastReceiver{
String username = null;
@Override
public void onReceive(Context context, Intent intent) {
//判断是否接收到了数据,并任务栏显示:
if (intent.getAction().equals(JPushInterface.ACTION_MESSAGE_RECEIVED)) {
Bundle bundle = intent.getExtras();
String title = bundle.getString(JPushInterface.EXTRA_TITLE);
String message = bundle.getString(JPushInterface.EXTRA_MESSAGE);
username = message;
String shuju =bundle.getString("type");
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
Log.i("info","___message_____123_______________________"+bundle.toString());
}
//判断任务栏的推送是否被点击 点击了后的操作!
if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) {
Bundle bundle = intent.getExtras();
int name1=bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID);
String title = bundle.getString(JPushInterface.EXTRA_TITLE);
String name =bundle.getString(JPushInterface.EXTRA_EXTRA);
String message = bundle.getString(JPushInterface.EXTRA_MESSAGE);
Log.i("info", "用户点击打开了通知--------120----->"+name.toString());
Mapp map =JSON.parseObject(name,Mapp.class);
Log.i("info", "用户点击打开了通知--------120----->"+map.toString());
String usernam = map.getType();
Log.i("info", "用户点击打开了通知--------120----->"+usernam);
//点击过后 把推送回来的数据 转发到消息显示页面,让该页面显示此消息!
Intent intent1 = new Intent();
intent1.putExtra("cgb",usernam);
intent1.setClass(context,Tuisongxianshi.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent1);
}
}
最后角标的实现:
下面就是手机角标的实现,只需要得到未读消息的条数,然后传入这两个方法就行
//获取手机品牌
String phoneName = android.os.Build.MODEL;
//vivo 角标设置
if(phoneName.equals("vivo Y51")){
Intent intent2 = new Intent("launcher.action.CHANGE_APPLICATION_NOTIFICATION_NUM");
intent2.putExtra("packageName",packageName);
String launchClassName =lancherActivityClassName;
intent2.putExtra("className", launchClassName);
//显示的角标数!
intent2.putExtra("notificationNum",a);
sendBroadcast(intent2);
}
//小米角标判断
else{
try {
Field field = notification.getClass().getDeclaredField("extraNotification");
Object extraNotification = field.get(notification);
Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
method.invoke(extraNotification, a);
} catch (Exception e) {
e.printStackTrace();
}
mNotificationManager.notify(0, notification);
}
此次学习的难点集合:
角标的实现:
每种手机品牌的角标实现方法并不一致,有的手机根本不支持角标,所以针对各种手机角标的问题,需要写入大量的代码,有的手机角标Dome 十分难找,所以写起来十分困难!
华为角标:
华为的角标只对大型的某些应用开发,所以在这里无法实现!
从保护用户体验的角度出发,华为角标暂时只对较大型的纯即时通讯类应用(例:聊天工具、邮箱)和大型企业的内部办公应用开放,还请各位开发者谅解!
Listview 的点击事件:
网上有很多 listview的点击Dome 但是并不都适用,这要看你listview里面的布局是什么样子的,如果只是简单的Textview 就可以直接 listview的对象点setOnItemClickListener(newAdapterView.OnItemClickListener()来实现点击事件,如果要加入Button等有需要另外的方法!
BroadcastReceiver 的取值问题:
当点击任务栏 进入if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) {
后,并取不到message 里面的值,最好吧 bundle。toString打印出来看一下,看里面传过来的究竟是什么,应为上面个IF取到了值,所以很容易忽略下面的if里面有可能是取不到值的,如果 不小心这里会怎么都找不出错来!
Intent 跳转新页面时,加入
intent1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK| Intent.FLAG_ACTIVITY_NEW_TASK);
这句!每次清除前面的activity ,让后面点击返回按钮时 会打开新的activity 这样让数据刷新!
列如:
Intent intent1 =new Intent(Tuisongxianshi.this,Home_page.class);
intent1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK| Intent.FLAG_ACTIVITY_NEW_TASK);
intent1.putExtra("tuisfh",name1);
startActivity(intent1);
实现BroadcastReceiver 接收到通知就更新 未读消息条数:
先在Home_page中 定义一个instance的成员变量!
staticHome_page instance;
然后在
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_page);instance = this;
在写一个instance的get方法:
public staticHome_page getInstance(){
return instance;
}
在BroadcastReceiver 中 得到消息的地方:
public voidonReceive(Context context,Intent intent) {
if (intent.getAction().equals(JPushInterface.ACTION_MESSAGE_RECEIVED)) {
Home_page.getInstance().runOnUiThread(newRunnable() {
@Override
public void run() {
// TODOAuto-generated method stub
//Toast.makeText(MessSendActivity.getInstance(),
// "frommessSend", 1).show();
TextView pb = (TextView) Home_page
.getInstance().findViewById(R.id.textViewjiaobiao);
String jiaobiaoshu = (String) pb.getText();
int a=Integer.parseInt(jiaobiaoshu);
pb.setText((a+1)+"");
}
});
}
就可以更新UI了!