1.消息推送机制
服务器器端需要变被动为主动,通知客户一些开发商认为重要的信息,无论应用程序是否正在运行或者关闭。
我想到了一句话:don't call me,i will call you!
qq今天在右下角弹出了一个对话框:"奥巴马宣布本拉登挂了…",正是如此。
自作聪明,就会带点小聪明,有人喜欢就有人讨厌。
2.独立进程
无论程序是否正在运行,我们都要能通知到客户,我们需要一个独立进程的后台服务。
我们需要一个独立进程的后台服务。
在androidmanifest.xml中注册service时,有一个android:process属性,如果这个属性以"."开头,则为此服务开启一个
全局的独立进程,如果以":"开头则为此服务开启一个为此应用私有的独立进程。举个具体的例子吧,我们新建了一个
application,创建了主进程com.cnblogs.tianxia,那么:
代码如下:
<!–下面会创建一个全局的com.cnblogs.tianxia.message的独立进程–>
<service android:name=".service.messageservice" android:label="消息推送" android:process=".message" />
<!–或者–>
<!–下面会创建一个应用私有的com.cnblogs.tianxia:message的独立进程–>
<service android:name=".service.messageservice" android:label="消息推送" android:process=":message" />
我们没必要建立一个全局的,本文选择第二种方案,创建一个当前应用私有的独立进程。
3.通知用户和点击查看
public class messageservice extends service {
//获取消息线程
private messagethread messagethread = null;
//点击查看
private intent messageintent = null;
private pendingintent messagependingintent = null;
//通知栏消息
private int messagenotificationid = 1000;
private notification messagenotification = null;
private notificationmanager messagenotificatiomanager = null;
public ibinder onbind(intent intent) {
return null;
}
@override
public int onstartcommand(intent intent, int flags, int startid) {
//初始化
messagenotification = new notification();
messagenotification.icon = r.drawable.icon;
messagenotification.tickertext = "新消息";
messagenotification.defaults = notification.default_sound;
messagenotificatiomanager = (notificationmanager)getsystemservice(context.notification_service);
messageintent = new intent(this, messageactivity.class);
messagependingintent = pendingintent.getactivity(this,0,messageintent,0);
//开启线程
messagethread = new messagethread();
messagethread.isrunning = true;
messagethread.start();
return super.onstartcommand(intent, flags, startid);
}
/**
* 从服务器端获取消息
*
*/
class messagethread extends thread{
//运行状态,www.3ppt.com下一步骤有大用
public boolean isrunning = true;
public void run() {
while(isrunning){
try {
//休息10分钟
thread.sleep(600000);
//获取服务器消息
string servermessage = getservermessage();
if(servermessage!=null&&!"".equals(servermessage)){
//更新通知栏
messagenotification.setlatesteventinfo(messageservice.this,"新消息","奥巴马宣布,本拉
登兄弟挂了!"+servermessage,messagependingintent);
messagenotificatiomanager.notify(messagenotificationid, messagenotification);
//每次通知完,通知id递增一下,避免消息覆盖掉
messagenotificationid++;
}
} catch (interruptedexception e) {
e.printstacktrace();
}
}
}
}
/**
* 这里以此方法为服务器demo,仅作示例
* @return 返回服务器要推送的消息,否则如果为空的话,不推送
*/
public string getservermessage(){
return "yes!";
}
}
其中messageactivity是点击跳转的activity,负责处理查看详细信息。
我们在其他activity中调用一下:
代码如下:
boolean ismessagepush = true;//不开启就设置为false;
…
if(ismessagepush){
startservice(new intent(this, messageservice.class))
};
运行一下:
4.停止服务
1 stopservice(new intent(myactivity.this,messageservice.class));
2 setmessagepush(false);//设置配置文件或数据库中flag为false
运行一下,停止服务后,却出乎意料的并没有停下来,怎么回事?是不是代码写错了?
代码没有错,错在我们停止了服务,却没有停止进程,退出线程。
5.退出线程
实践证明,thread的stop()方法并不可靠。但是我们有其他的办法。
在代码面前,程序员就是上帝。
退出线程有两种方法。
第一种方法,强制退出。
//杀死该线程所在的进程,自然就退出了
system.exit(0);
第二种方法,设置isrunning为false。
//前面说到了isrunning这个标志,设置为false后,线程的执行就从while循环中跳出来了,然后自然结束掉了
messagethread.isrunning = false;
综合一下,我们在messageservice中重载ondestroy()方法如下:
代码如下:
@override
public void ondestroy() {
system.exit(0);
//或者,二选一,推荐使用system.exit(0),这样进程退出的更干净
//messagethread.isrunning = false;
super.ondestroy();
}
实例
代码如下 | 复制代码 |
public String getLocalIpAddress() { public String getLocalMacAddress(Context context) { |
安卓4.0系统的手机,按上面的方法默认会先获取到ipv6的地址,有时候我们只想要ipv4的地址
代码如下 | 复制代码 |
/** * 用来获取手机拨号上网(包括CTWAP和CTNET)时由PDSN分配给手机终端的源IP地址。 * * @return * @author SHANHY */ public static String getPsdnIp() { try { for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) { //if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet6Address) { return inetAddress.getHostAddress().toString(); } } } } catch (Exception e) { } return ""; } |
当控件本身layout_width设置为fill_parent的时候,layout_weight数值越小,所占空间越大,但尽可能大是有限度的,即fill_parent.
当控件本身layout_width设置为wrap_content的时候,layout_weight数值越小,所占空间也越小,但这个小是有限度的,即wrap_content.
例子
看了一下源码,虽说不太懂,但了解了下大概意思,按照自己的理解总结一下,直接写一下简化的代码吧(下面的代码是LinearLayout源文件中一部分的精简,变量名称含义可能不准确,为叙述方便暂作此解释):
代码如下 | 复制代码 |
//Either expand children with weight to take up available space or if (child == null || child.getVisibility() == View.GONE) { float childExtra = lp.weight; |
变量含义
widthSize: LinearLayout的宽度
mTotalLength: 所有子View的宽度的和(还没用考虑layout_weight)
totalWeight: 所有子View的layout_weight的和
mWeihtSUm: LinearLayout的android:weightSum属性
过程分析:
首先计算出额外空间(可以为负)如果额外空间不为0并且有子View的layout_weight不为0的话按layout_weight分配额外空间:
代码如下 | 复制代码 |
int delta = widthSize - mTotalLength; |
如果LinearLayout设置了weightSum则覆盖子View的layout_weight的和:
代码如下 | 复制代码 |
float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; |
然后遍历LinearLayout的子元素,如果不为null且Visibility不为GONE的话,取得它的LayoutParams,如果它的layout_weight大于0,根据weightSum与它的weight计算出分配给它的额外空间
代码如下 | 复制代码 |
if (childExtra > 0) { int childWidth = child.getMeasuredWidth() + share; |
例子
代码如下 | 复制代码 |
|
在Android开发中,我们的Activity都不免要用到很多的View部件,而对于每一个View我们都要findViewById,设置监听器,获取用户输入的结果等操作。如果我们细心想想,这些琐碎的操作是不是跟这个Activity的处理逻辑没有很大的关系呢?很多的Activity中都要用到一些常见的View组合,能不能把他们抽象出来形成一种可以复用的复合组件呢?
这篇文章就是基于这种想法,开发了一个简单的组件,对于Android新手来说,可以作为一种参考吧。
EditTextWithLabel组件类定义:(EditTextWithLabel.java)
代码如下 | 复制代码 |
package com.raysmond.component; import android.content.Context; public class EditTextWithLabel extends LinearLayout{ |
EditTextWithLabel组件的布局xml(edit_text_with_label.xml)
代码如下 | 复制代码 |
<?xml version="1.0" encoding="utf-8"?> <EditText |
使用EditTextWithLabel复合组件,主Activity的XML (activity_main.xml)
代码如下 | 复制代码 |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <TextView </RelativeLayout> |
使用EditTextWithLabel复合组件,主Activity类(MainActivity.java)
代码如下 | 复制代码 |
package com.raysmond.activity; import com.raysmond.component.EditTextWithLabel; import android.os.Bundle; public class MainActivity extends Activity { |
Demo:
本文章来给大家介绍Android 利用Application对象存取公共数据,有需要了解学习的同学不防进入参考。Android系统在运行每一个程序应用的时候,都会创建一个Application对象,用于存储与整个应用相关的公共变量。一个Android应用只会生成一个Application对象,在不用的Activity中获取的Application对象是一样的,所以Application对象是一个单例(SingleTon)。Application对象非常适合用于存储一些与整个应用相关数据,例如应用版本,应用登录账户,数据缓存等。
利用Application对象存储公共数据或数据传递
在android开发中,activity的切换是很频繁的,差不多可以和一个网站中不同网页之间的切换一样。那么不同的activity之间需要存储公共信息(如只有一个当前登录用户)以及数据传递等。下面就是一种利用Application对象存储登录用户信息的方法,可以发现这很方便不同的activity获取登录用户信息。
首先,新建一个java类继承Application类:MyApplication.java
代码如下 | 复制代码 |
package com.example.applicationtest; import android.app.Application; public class MyApplication extends Application { |
在AndroidManifest.xml中指定应用的application对象
代码如下 | 复制代码 |
<?xml version="1.0" encoding="utf-8"?> <uses-sdk <application <category android:name="android.intent.category.LAUNCHER" /> </manifest> |
在activity中使用application对象, 使用Activity的getApplication()方法。
代码如下 | 复制代码 |
package com.example.applicationtest; import android.os.Bundle; public class MainActivity extends Activity { } |
可以发现通过Application对象,在不同的Activity之间可以方便地实现数据共享。这比在每次切换activity时通过Bundle传递数据方便多了。
传统的利用Bundle在activity之前传递数据的方式
假设我们有两个Activity: Activity1和Activity2,Activity1切换到Activity2并传递用户信息。
代码如下 | 复制代码 |
Activity1.java package com.example.applicationtest; import android.os.Bundle; public class Activity1 extends Activity { @Override } package com.example.applicationtest; import android.os.Bundle; public class Activity2 extends Activity { @Override } |
我们可以发现这种传递数据的方式比较繁琐,特别是当Activity众多,切换很频繁的时候。整个应用的的公共数据(如登录信息)在不同的activity之间都一样且都需要用到时,利用Application对象更加简洁和方便