好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

【Parse】开发笔记(4)—— Push Notifications(上)

【Parse】开发笔记(4)—— Push Notifications(上)

【Parse】开发笔记(4)—— Push Notifications(上)

前言

合理的使用Push服务,能极大提高用户活跃度,本博《Parse Push快速入门指南》仅简单介绍和使用了一下Parse的推送服务,这里介绍更多的使用方法和技巧。系列文章分两篇来介绍Push服务,分别针对所有用户(上)和渠道定制用户(下)。

声明
欢迎转载,但请保留文章原始出处:) 
博客园:http://www.cnblogs.com

农民伯伯: http://over140.cnblogs.com  

正文

一、系列

1.1 【Parse】开发笔记(1)—— 准备

1.2 【Parse】开发笔记(2)—— 从Mysql导入数据到Parse Data

1.3 【Parse】开发笔记(3)—— 实现查找附近的功能(LBS)  

   

二、准备

2.1官网的Android Push Notifications

https://www.parse.com/tutorials/android-push-notifications

2.2  【Android】Parse Push快速入门指南

http://www.cnblogs.com/over140/archive/2013/03/19/2968560.html    

三、 功能

3.1准备

AndroidManifest.xml

     < uses-permission  android:name ="android.permission.INTERNET"   />
     < uses-permission  android:name ="android.permission.ACCESS_NETWORK_STATE"   />
     < uses-permission  android:name ="android.permission.RECEIVE_BOOT_COMPLETED"   />
     < uses-permission  android:name ="android.permission.VIBRATE"   />


     < application
         android:name ="com.nmbb.lol.LOLApplication"
        android:allowBackup ="true"
        android:icon ="@drawable/app_icon"
        android:label ="@string/app_name"
        android:theme ="@style/AppTheme"   >
         < service  android:name ="com.parse.PushService"   />

         < receiver  android:name ="com.parse.ParseBroadcastReceiver"   >
             < intent-filter >
                 < action  android:name ="android.intent.action.BOOT_COMPLETED"   />
                 < action  android:name ="android.intent.action.USER_PRESENT"   />
             </ intent-filter >
         </ receiver >
        
         < receiver  android:name =".receiver.ReceiverPush"   >
             < intent-filter >
                 < action  android:name ="com.nmbb.lol.push"   />
             </ intent-filter >
         </ receiver >
     </ application >

  代码说明:

注意,这只是代码片段,加入项目做相应的调整。 

a)、 android.permission.RECEIVE_BOOT_COMPLETED权限非必须,可以把这个和ParseBoradcastReceiver的BOOT_COMPLETED一起去掉,但重启后可能就无法接收推送了,需要打开一次应该才可以。(我就想这样!能少用一个权限就少一个)注意消息不会丢失,会在下一次一起收到。

b)、PushService必须要注册,否则无法使用 

c)、ReceiverPush后面要用到,主要用于接收广播,方便自己处理推送数据。 

Application

    @Override
     public   void  onCreate() {
         super .onCreate();

        Parse.initialize( this , "Application ID",
                "Client Key");
         //  PushService.subscribe(this, "", WebActivity.class);
        PushService.setDefaultPushCallback( this , WebActivity. class );
        ParseInstallation.getCurrentInstallation().saveInBackground();
    }

 代码说明:

除了配置AndroidManifest.xml,仅在Application的onCreate中加入这三行代码即可。

a)、注意最后一行好像是最近更新加上的,否则无法接收到Push,大意是登记注册的意思,可以在Data Browser中对象Installation中看到。

b)、setDefaultPushCallback第二个参数,表示点击Notifacation时处理的Activity

3.2以通知(Notification)的形式显示推送信息(状态栏显示通知)

进入Parse后台的Push Notifications,点击Send a push 

3.2.1以消息(Message)的形式发送

通过查看发送报告,发现其实也是以JSON数据发送的,不过只包含alert节点。 

3.2.2以JSON形式发送 

 

title和alert分别对应Android Notification对象的标题和消息,不设置title就默认显示APP的名称。

最后点击Send Notification就可以了,顺利的话可以看到设备上收到Notification。

3.2.3处理通知信息

当点击状态栏的通知时,会默认跳转到 setDefaultPushCallback指定的Activity中,可以从Intent中解析Push的数据:

 

直接从getIntent(). getStringExtra("com.parse.Data")即可取到上面的信息,然后完成业务逻辑即可。

3.2自定义以广播的形式后台接受推送信息(状态栏不显示通知)

只要以JSON格式发送,并且不包含title和alert节点,即不会显示Notification了(大家可以反编译看一下 StandardPushCallback类 ),那么如何接受Push的数据呢?

3.2.1首先注册Boradcast,设置Intent-filter,这里设置的action是com.nmbb.lol.push,代码上面已经给出。

3.2.2json数据:

{"action":"com.nmbb.lol.push","url":"http://v.youku.com/player/getRealM3U8/vid/XNTU1NjkzMDAw/type/mp4/v.m3u8"}

必须包含action和匹配的值,才能接受到推送广播。接下来就可以做你想做的事情了!这里贴一下Boradcast代码:

public   class  ReceiverPush  extends  BroadcastReceiver {

    @Override
     public   void  onReceive(Context context, Intent intent) {
         if  (context !=  null  && intent !=  null
                && "com.nmbb.lol.push".equals(intent.getAction())) {
             try  {
                JSONObject json =  new  JSONObject(intent.getExtras().getString(
                        "com.parse.Data"));
                String title = json.optString("title");
                String message = json.optString("message");
                String action = json.optString("action");
                String url = json.optString("url");
                
                ToastUtils.showLongToast(message);
                
            }  catch  (JSONException e) {
                Logger.e(e);
            }
        }
    }

}

3.3其他注意

a).发送消息时注意右上角的 recipients的数量,表示收到推送用户的数量。

b).注意在Settings中开启Client push

c).今天还碰到一个特别奇怪的问题,死活收不到推送,不知道是不是和APP名称设置为中文有关系,删了重建弄个英文的又好了。 

四、文章

Android Push Notifications In Parse: A deep overview

 

 

分类:  1、Android

标签:  android push ,  android parse push ,  android push json ,  android parse push json

神奇的Timer

最近的一个项目有一些地方需要用到定时功能,在设计过程中,突然发现.net的Timer类居然还有很多我以前没有用过的功能,这里就跟大家分享一下

注:这里的Timer类特指 System.Threading.Timer类

情景1:我需要服务器在每天的00:00点执行一个操作

我当开始想到的方法很2b,居然是设定定时器每个1分钟去检查时间,如果当前时间与00:00相差不超过1分钟时,就执行操作!!!由于这段的代码太过2b,所以就不放上来了!

我都不知道自己刚开始怎么会想到如此2的设计,几乎刚把代码写完我自己就把这个方案个否定了,极度浪费资源不说,还不能精准的在00:00执行操作!

于是我又一次查看了msdn,msdn真是编程神器啊,现在我离开了它简直是寸步难行了,我惊喜的发现Timer的构造函数中有这样一个参数

这个dueTime参数不正是我需要的吗?只不过我以前一般忽略了这个参数,直接将其置为0了!所以我立刻写下了下面的代码

 1   var  span = DateTime.Today.AddDays( 1 ) -  DateTime.Now;
  2   var  timer =  new  Timer(callback,  null , ( int )span.TotalMilliseconds,  24  *  3600  *  1000 );

于是在第二天的00:00,定时器就开始执行,然后每隔24小时执行一次,这样就完美的达到了情景中的目标!

情景2:我需要每个5分钟保存一次RichT extBox中的内容

这实际上就是一个类似Word的自动保存功能,刚开始我觉得很简单,不就是定义一个5分钟的定时器就了事吗?后来想想不这么简单,因为如果用户不在 RichT extBox更改任何内容,这是还是隔5分钟保存一次就是资源浪费!于是可以将上述情景更加精确的描述为:

在用户每次对RichTextBox的内容修改之后的5分钟时,对RichTextBox中内容保存一次!

这样又如何去实现呢?于是我又一次查看了MSDN,果然没让我失望,MSDN又一次给了我惊喜,请看下面的MSDN说明

这句话简直就是为了解决情境中的问题说的啊!于是我立刻写下了下面的代码:

  1  System.Threading.Timer timer =  null  ;
   2           bool  needSave =  false  ;
   3           private   void  richTextBox1_TextChanged( object   sender, EventArgs e)
   4           {
   5               if  (timer ==  null  )
   6                  timer =  new  System.Threading.Timer(Callback,  null ,  5  *  60  *  1000 ,  0  );
   7               else   if   (needSave)
   8               {
   9                  needSave =  false  ;
  10                  timer.Change( 5  *  60  *  1000 ,  0  );
  11               }
  12           }
  13           void  Callback( object   state)
  14           {   
  15               Save();
  16              needSave =  true  ;
  17          }

 将period参数置为0,就意味着定时器只会执行一次,此时定时功能是依靠参数dueTime来实现的,Change函数可以重启定时功能,并且每次RichTextBox中有内容的改变,定时器就会被重置,这样就完美的解决了情境中的问题了! 
        

 

 

 

标签:  c# ,  winform ,  Timer

Android学习笔记49:Socket编程实现简易聊天室

 

在之前的博文中,我们学习了在Android开发中,如何使用标准Java接口HttpURLConnection和Apache接口HttpClient进行HTTP通信。

  本篇博文将主要对Socket进行介绍,并通过Socket编程实现一个简易聊天室的案例。

 

1.Socket基础知识

  Socket(套接字)用于描述IP地址和端口,是通信链的句柄,应用程序可以通过Socket向网络发出请求或者应答网络请求。

  Socket是支持TCP/IP协议的网络通信的基本操作单元,是对网络通信过程中端点的抽象表示,包含了进行网络通信所必需的5种信息:连接所使用的协议、本地主机的IP地址、本地进程的协议端口、远地主机的IP地址以及远地进程的协议端口。

1.1 Socket的传输模式

  Socket有两种主要的操作方式:面向连接的和无连接的。

  面向连接的Socket操作就像一部电话,Socket必须在发送数据之前与目的地的Socket取得连接,一旦连接建立了,Socket就可以使用一个流接口进行打开、读写以及关闭操作。并且,所有发送的数据在另一端都会以相同的顺序被接收。

  无连接的Socket操作就像一个邮件投递,每一个数据报都是一个独立的单元,它包含了这次投递的所有信息(目的地址和要发送的内容)。在这个模式下的Socket不需要连接目的地Socket,它只是简单的投出数据报。

  由此可见,无连接的操作是快速高效的,但是数据安全性不佳;面向连接的操作效率较低,但数据的安全性较好。

  本文主要介绍的是面向连接的Socket操作。

1.2 Socket的构造方法

  Java在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的Socket客户端和服务器端。

  Socket的构造方法如下:

  (1)Socket(InetAddress address, int port);

  (2)Socket(InetAddress address, int port, boolean stream);

  (3)Socket(String host, int port);

  (4)Socket(String host, int port, boolean stream);

  (5)Socket(SocketImpl impl);

  (6)Socket(String host, int port, InetAddress localAddr, int localPort);

  (7)Socket(InetAddress address, int port, InetAddrss localAddr, int localPort);

  ServerSocket的构造方法如下:

  (1)ServerSocket(int port);

  (2)ServerSocket(int port, int backlog);

  (3)ServerSocket(int port, int backlog, InetAddress bindAddr);

  其中,参数address、host和port分别是双向连接中另一方的IP地址、主机名和端口号;参数stream表示Socket是流Socket还是数据报Socket;参数localAddr和localPort表示本地主机的IP地址和端口号;SocketImpl是Socket的父类,既可以用来创建ServerSocket,也可以用来创建Socket。

  如下的代码在服务器端创建了一个ServerSocket:

 1     try   {
  2    ServerSocket serverSocket =  new  ServerSocket(50000);     //  创建一个ServerSocket,用于监听客户端Socket的连接请求 
 3         while ( true  ) {
  4            Socket socket = serverSocket.accept();         //  每当接收到客户端的Socket请求,服务器端也相应的创建一个Socket
  5         //  todo开始进行Socket通信 
 6         }
  7    } catch   (IOException e) {
  8         e.printStackTrace();
  9    }

  其中,50000是我们自己选择的用来进行Socket通信的端口号,在创建Socket时,如果该端口号已经被别的服务占用,将会抛出异常。

  通过以上的代码,我们创建了一个ServerSocket在端口50000监听客户端的请求。accept()是一个阻塞函数,就是说该方法被调用后就会一直等待客户端的请求,直到有一个客户端启动并请求连接到相同的端口,然后accept()返回一个对应于该客户端的Socket。

  那么,如何在客户端创建并启动一个Socket呢?

 1     try   {
  2        socket =  new  Socket("192.168.1.101", 50000);     //  192.168.1.101是服务器的IP地址,50000是端口号
  3       //  todo开始进行Socket通信 
 4    }  catch   (IOException e) {
  5         e.printStackTrace();
  6  }

    至此,客户端和服务器端都建立了用于通信的Socket,接下来就可以由各自的Socket分别打开各自的输入流和输出流进行通信了。

1.3输入流和输出流

  Socket提供了方法getInputStream()和getOutPutStream()来获得对应的输入流和输出流,以便对Socket进行读写操作,这两个方法的返回值分别是InputStream和OutPutStream对象。

  为了便于读写数据,我们可以在返回的输入输出流对象上建立过滤流,如PrintStream、InputStreamReader和OutputStreamWriter等。

1.4关闭Socket

  可以通过调用Socket的close()方法来关闭Socket。在关闭Socket之前,应该先关闭与Socket有关的所有输入输出流,然后再关闭Socket。

 

2.简易聊天室

  下面就来说说如何通过Socket编程实现一个简易聊天室。客户端完成后的运行效果如图1所示。

  图1 运行效果

  在该客户端的界面中,使用了一个TextView控件来显示聊天记录。为了方便查看,将两个用户也放到了一个界面中,实际上应该启动两个模拟器,分别作为两个用户的客户端,此处是为了方便操作才这么做的。

2.1服务器端ServerSocket的实现

  在该实例中,我们在MyEclipse中新建了一个Java工程作为服务器端。在该Java工程中,我们应该完成以下的操作。

  (1)指定端口实例化一个ServerSocket,并调用ServerSocket的accept()方法在等待客户端连接期间造成阻塞。

  (2)每当接收到客户端的Socket请求时,服务器端也相应的创建一个Socket,并将该Socket存入ArrayList中。与此同时,启动一个ServerThread线程来为该客户端Socket服务。

  以上两步操作,可以通过以下的代码来实现:

  1     /* 
  2      * Class    :   MyServer类,用于监听客户端Socket连接请求
   3      * Author   :   博客园-依旧淡然
   4      */ 
  5     public   class   MyServer {
   6        
  7         //  定义ServerSocket的端口号 
  8         private   static   final   int  SOCKET_PORT = 50000 ;
   9         //  使用ArrayList存储所有的Socket 
 10         public   static  ArrayList<Socket> socketList =  new  ArrayList<Socket> ();
  11    
 12         public   void   initMyServer() {
  13             try   {
  14           //  创建一个ServerSocket,用于监听客户端Socket的连接请求 
 15                ServerSocket serverSocket =  new   ServerSocket(SOCKET_PORT);
  16                 while ( true  ) {
  17                     //  每当接收到客户端的Socket请求,服务器端也相应的创建一个Socket 
 18                    Socket socket =  serverSocket.accept();
  19                     socketList.add(socket);
  20                     //  每连接一个客户端,启动一个ServerThread线程为该客户端服务 
 21                     new  Thread( new   ServerThread(socket)).start();
  22                 }
  23            } catch   (IOException e) {
  24                 e.printStackTrace();
  25             }
  26         }
  27        
 28         public   static   void   main(String[] args) {
  29            MyServer myServer =  new   MyServer();
  30             myServer.initMyServer();
  31         }
  32    }

    (3)在启动的ServerThread线程中,我们需要将读到的客户端内容(也就是某一个客户端Socket发送给服务器端的数据),发送给其他的所有客户端Socket,实现信息的广播。ServerThread类的具体实现如下:

  1     public   class  ServerThread  implements   Runnable {
   2    
  3         //  定义当前线程所处理的Socket 
  4         private  Socket socket =  null  ;
   5         //  该线程所处理的Socket对应的输入流 
  6         private  BufferedReader bufferedReader =  null  ;
   7        
  8         /* 
  9          * Function  :    ServerThread的构造方法
  10          * Author    :    博客园-依旧淡然
  11          */ 
 12         public  ServerThread(Socket socket)  throws   IOException {
  13             this .socket =  socket;
  14             //  获取该socket对应的输入流 
 15            bufferedReader =  new  BufferedReader( new   InputStreamReader(socket.getInputStream()));
  16         }
  17        
 18         /* 
 19          * Function  :    实现run()方法,将读到的客户端内容进行广播
  20          * Author    :    博客园-依旧淡然
  21          */ 
 22         public   void   run() {
  23             try   {
  24                String content =  null  ;
  25                 //  采用循环不断地从Socket中读取客户端发送过来的数据 
 26                 while ((content = bufferedReader.readLine()) !=  null  ) {
  27                     //  将读到的内容向每个Socket发送一次 
 28                     for  (Socket socket : MyServer.socketList) {
  29                         //  获取该socket对应的输出流 
 30                        PrintStream printStream =  new   PrintStream(socket.getOutputStream());
  31                         //  向该输出流中写入要广播的内容 
 32                         printStream.println(packMessage(content));
  33                        
 34                     }
  35                 }
  36            }  catch  (IOException e) {
  37                 e.printStackTrace();
  38             }
  39         }
  40        
 41         /* 
 42          * Function  :    对要广播的数据进行包装
  43          * Author    :    博客园-依旧淡然
  44          */ 
 45         private   String packMessage(String content) {
  46            String result =  null  ;
  47            SimpleDateFormat df =  new  SimpleDateFormat("HH:mm:ss");     //  设置日期格式 
 48             if (content.startsWith("USER_ONE" )) {
  49                String message = content.substring(8);         //  获取用户发送的真实的信息 
 50                result = "\n" + "往事如风  " + df.format( new  Date()) + "\n" +  message;
  51             }
  52             if (content.startsWith("USER_TWO" )) {
  53                String message = content.substring(8);         //  获取用户发送的真实的信息 
 54                result = "\n" + "依旧淡然  " + df.format( new  Date()) + "\n" +  message;
  55             }
  56             return   result;
  57         }
  58    
 59    }

    其中,在packMessage()方法中,我们对要广播的数据进行了包装。因为要分辨出服务器接收到的消息是来自哪一个客户端Socket的,我们对客户端Socket发送的消息也进行了包装,方法是在消息的头部加上"USER_ONE"来代表用户"往事如风",在消息的头部加上"USER_TWO"来代表用户"依旧淡然"。 

  至此,服务器端的ServerSocket便算是创建好了。

2.2客户端Socket的实现

  接下来,我们便可以在Android工程中,分别为用户"往事如风"和"依旧淡然"创建一个客户端Socket,并启动一个客户端线程ClientThread来监听服务器发来的数据。

  这一过程的具体实现如下:

  1       /* 
  2        * Function   :   初始化Socket
   3        * Author     :   博客园-依旧淡然
   4        */ 
  5       private   void   initSocket() {
   6           try   {
   7              socketUser1 =  new  Socket(URL_PATH, SOCKET_PORT);             //  用户1的客户端Socket 
  8              socketUser2 =  new  Socket(URL_PATH, SOCKET_PORT);             //  用户2的客户端Socket 
  9              clientThread =  new  ClientThread();         //  客户端启动ClientThread线程,读取来自服务器的数据 
 10               clientThread.start();
  11          }  catch   (IOException e) {
  12               e.printStackTrace();
  13           }        
  14      }

    ClientThread的具体实现和服务器端的ServerThread线程相似,唯一的区别是,在ClientThread线程中接收到服务器端发来的数据后,我们不可以直接在ClientThread线程中进行刷新UI的操作,而是应该将数据封装到Message中,再调用MyHandler对象的sendMessage()方法将Message发送出去。这一过程的具体实现如下:

  1       /* 
  2        * Function   :   run()方法,用于读取来自服务器的数据
   3        * Author     :   博客园-依旧淡然
   4        */ 
  5     public   void   run() {
   6     try   {
   7            String content =  null  ;
   8             while ((content = bufferedReader .readLine()) !=  null  ) {
   9                Bundle bundle =  new   Bundle();
  10                 bundle.putString(KEY_CONTENT, content);
  11                Message msg =  new   Message();
  12                msg.setData(bundle);             //  将数据封装到Message对象中 
 13                 myHandler.sendMessage(msg);
  14             }
  15        }  catch   (Exception e) {
  16             e.printStackTrace();
  17         }
  18    }

    最后,我们在UI主线程中创建一个内部类MyHandler,让它继承Handler类,并实现handleMessage()方法,用来接收Message消息并处理(刷新UI)。MyContent是一个用来保存聊天记录的类,提供了get和set接口,其中,set接口设置的本条聊天记录,而get接口获得的是全部的聊天记录。具体的实现如下:

  1       /* 
  2        * Class      :   内部类MyHandler,用于接收消息并处理
   3        * Author     :   博客园-依旧淡然
   4        */ 
  5       private   class  MyHandler  extends   Handler {
   6           public   void   handleMessage(Message msg) {
   7              Bundle bundle = msg.getData();             //  获取Message中发送过来的数据 
  8              String content =  bundle.getString(KEY_CONTENT);
   9              MyContent.setContent(content);             //  保存聊天记录 
 10               mTextView.setText(MyContent.getContent());
  11           }
  12      }

    至此,客户端的Socket也编写完成了。

作者: 依旧淡然

邮箱:mls19880708@163.com

博客: http://www.cnblogs.com/menlsh/

本文版权归作者所有,未经作者同意,严禁转载及用作商业传播,否则将追究法律责任。

 

 

标签:  Android

 

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于【Parse】开发笔记(4)—— Push Notifications(上)的详细内容...

  阅读:53次