android 推送的三大方法
2018-10-22 21:01:00 weixin_33851429 阅读数 40
2657154-5970d28b9709bbd1.png

写博客就好像吃甜品,明知道发胖还忍不住,胖并快乐着。
我写东西基本就是在各种总结别人的文章和自己的理解,所以可能不是很专业。
在事件分发篇,我们扯到了window和DecorView ,这次我们引入一个ViewRoot。
其实这块还是很有意思的,后面我们讲handle这块还能和这里有关。

ViewRoot

ViewRoot 或者说对应的 ViewRootImlp 类,它其实是连接 WindowManger 和 DecorView 的桥梁。View 的三大流程都是通过 ViewRoot 来完成的。
Activity创建完毕后,会讲DecorView添加到window,同时创建了ViewRootImlp,将它和DecorView绑定。


2657154-c8a762ab3ad8c263.png

View的绘制是从ViewRootImlp的performTraversals开始的,经过measure.layout.draw三方法最终将一个View绘制出来。measure测量View宽高。layout确定View位置,draw负责绘制。


2657154-ab07bd698ad3a3c9.png

从上图我们能看到,performTraversals调用的时候,调用了performMeasure.performLayout.performDraw 三方法,然后调用最顶级View的Measure,Layout,Draw,顶级View的Measure调用onMersure对子view进行测量,子view对自己子view进行一样的操作。Layout,Draw也是一样,遍历进行处理,不过performDraw的传递是在draw方法种用了dispatchDeaw完成的,不过没啥区别。
这里用我们自己的话总结,其实就是ViewRootImlp自己的测量,布局,绘制的方法掉用顶级view的测量,布局,绘制的方法,顶级view又对自己下面子view进行了递归的测量,布局和绘制。ViewRootImlp三方法跑完,view就有了自己的宽高和位置,才能绘制完毕显示到页面上。
到现在为止 我们大体上了解了,Activity有一个window,收到事件以后,window持有DecorView,DecorView在被添加到window到时候,会产生一个ViewRootImlp,ViewRootImlp在调用performTraversals(遍历表演)的时候会调用顶级view的测量,布局和绘制,然后顶级view会挨个调用自己子布局的测量布局和绘制,这样一个页面就展现出来了。

DecorView

DecorView 继承自 FrameLayout,是一个 ViewGroup。在整个 ViewTree 中, DecorView 是整个 ViewTree 的顶层 View。View 的所有事件,都先经过 DecorView,然后再传递给 View。
DecorView 在一般情况下,内部会包含一个竖直的 LInearLayout,里面有上下两部分,上面是标题栏,下面是内容,内容布局有一个默认的 id: content。
我们在 Activity 中 通过 setContentView() 方法设置的布局,其实就是添加到了内容部分里。如果我们想获取到内容布局的话,可以通过如下方法获取:
ViewGroup content = (ViewGroup) findViewById(android.R.id.content)
想获取到我们设置的 View 的话,可以通过如下方式获取: View childAt = content.getChildAt(0);
顶级View调用三大方法其实也是调用了View自带的onMeasure,onLayout和onDraw。

MeasureSpec

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

其实我一一直好奇MeasureSpec到底是个啥?
MeasureSpec其实是一个32位数int值, 高二位指的是SpeceMode,低30位指的是SpeceSize。
SpeceMode就是测量模式,这玩意就是我们自定义view的时候,想知道是很准却的多少dp?还是我们写的match_parent之类的。android 将SpeceMode和SpeceSize和在了一起。
android 里面SpeceMode有三种模式

  • UNSPECIFIED(未指定):父元素不对子元素施加任何束缚,子元素可以得到任意想要的大小;
  • EXACTLY(完全):父元素决定子元素的确切大小,子元素将被限定在给定的边界里而忽略它本身的大小;
  • AT_MOST(最多):子元素至最多达到指定大小的值。

MeasureSpec和LayoutParamas有什么关系呢

对于顶级的DecorView,它的MeasureSpec是由窗口尺寸和自身的LayoutParamas决定大小。
普通View是由父容器的MeasureSpec和自身的LayoutParamas决定。
这块其实有点晕,可以这么理解,MeasureSpec决定了控件的大小,DecorView是由窗口决定的和自己大小决定,别人限制不了,但是普通View哪怕写了match也得看父容器给不给你这么大。
DecorView


2657154-6deb653a887fc374.png

普通View


2657154-0afcd58488700d8e.png

当普通View是精确模式的时候,不管父的MeasureSpec是啥,View就是那么大。
当普通View是match模式时候,父容器是精确模式,那么view大小就是剩下的大小。
如果父容器也是match模式,那么view也是最大模式,但是最大不能超过父容器剩余空间。
当view是warp模式的时候,不管父容器是什么模式,view总是最大模式,但是不能超过父容器剩下的空间。
UNSPECIFIED 这个模式一般用于在Measure过程中一般不需要理睬。
总结一波就是精确模式,我多大就是多大。 match模式,最大不能超过父容器剩余空间,模式和父容器一样。warp模式,最大化,不能超过父容器。

onMeasure

该方法是一个 finall 方法,所以不能被重写。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
            getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
public static int getDefaultSize(int size, int measureSpec) {
    int result = size;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    switch (specMode) {
    case MeasureSpec.UNSPECIFIED:
        result = size;
        break;
    case MeasureSpec.AT_MOST:
    case MeasureSpec.EXACTLY:
        result = specSize;
        break;
    }
    return result;
}

从上述代码上可以看到,关于我们关心的 AT_MOST 和 EXACTLY 测量模式,其实 getDefaultSize() 方法返回的就是 MeasureSpec 的 specSize。
到这里也就理解了,为什么当我们在布局中写 wrap_content,如果不重写 onMeasure() 方法,则默认大小是父控件的可用大小了。 当我们在布局中写 wrap_content 时,那么测量模式就是: AT_MOST,在该模式下,它的宽高等于 specSize。而 specSize 由 ViewGroup 传递过来时就是 parentSize,也就是父控件的可用大小。 当我们在布局中写 match_parent 时,那么不用多说,宽高当然也是 parentSize。这时候,我们只需对 AT_MOST 测量模式进行处理。
其实我们再自定义一个view的时候,其实如果父布局没有固定宽高时候,我们希望我们的控件wrap_content模式可以有个固定宽高,不然我们的view永远是最大模式。
如果父控件传递给的MeasureSpec的mode是MeasureSpec.UNSPECIFIED,就说明,父控件对自己没有任何限制,那么尺寸就选择自己需要的尺寸size
如果父控件传递给的MeasureSpec的mode是MeasureSpec.EXACTLY,就说明父控件有明确的要求,希望自己能用measureSpec中的尺寸,这时就推荐使用MeasureSpec.getSize(measureSpec)
如果父控件传递给的MeasureSpec的mode是MeasureSpec.AT_MOST,就说明父控件希望自己不要超出MeasureSpec.getSize(measureSpec),如果超出了,就选择MeasureSpec.getSize(measureSpec),否则用自己想要的尺寸就行了。

public class TestView extends View {
    private static final String TAG = "TestView";

    public TestView(Context context) {
        super(context);
    }

    public TestView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = 300;//默认值300
        int height=300;
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        switch (widthMode) {
            case MeasureSpec.AT_MOST://当得不到精确值的时候就300
                width = 300;
                break;
            case MeasureSpec.EXACTLY://精确模式采用系统返回的数值
                width = MeasureSpec.getSize(widthMeasureSpec);
                break;
            case MeasureSpec.UNSPECIFIED:
                break;


        }
        switch (heightMode) {
            case MeasureSpec.AT_MOST:
                height = 300;
                break;
            case MeasureSpec.EXACTLY:
                height = MeasureSpec.getSize(heightMeasureSpec);
                break;
            case MeasureSpec.UNSPECIFIED:
                break;


        }

        //设置
        setMeasuredDimension(width, height);
    }


}

setMeasuredDimension(width, height);
都为wrap_content的时候,父布局和我们的View一样大


2657154-917628c85ae35a68.png

父布局固定的时候,我们按照自己默认大小。


2657154-a96571f57916bfb7.png

父布局固定的时候,我们match


2657154-74f37a7b1fc91035.png

父布局固定,我们固定的时候


2657154-89edb560d46955e3.png

父布局和我们都match的时候
2657154-9b12d982f6f4c054.png

在onMeasure方法里我们主要去处理自定义View的宽高。

ViewGropu的measure

对于ViewGropu来说,完成除了自己的measure过程外,会遍历子元素的measure过程,ViewGropu是一个抽象类,没重写View的onMeasure方法,但是它提供了一个meausreChildren的方法。


2657154-74a2da5e53894f58.png
android艺术探索

取出子元素的LayoutParams,通过getChildeMeasureSpec创建子元素的MeasureSpce,传递给View去测量。
View的具体宽高在页面的onCreat,onMeasure,onStart方法都是不能准确获取的,因为View的measure不能保证和生命周期同步。
想测量准确,第一个方法onWindowFocusChanged,页面获得焦点失去焦点的时候都会被调用

  @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        int width = text.getWidth();
    }

第二个方法是View.post,发送一个runnable到消息队列尾部。

  text.post(new Runnable() {
            @Override
            public void run() {
                int width = text.getWidth();
            }
        });

第三个是ViewTreeObserver,但是可能会被调用多次。

 ViewTreeObserver viewTreeObserver = text.getViewTreeObserver();
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int width = text.getWidth();
            }
        });

第四种是View.measure,比较麻烦不建议使用。

onLayout

layout可以说是三大方法里面最简单的一个了,layout会确定View自己的位置,onLayout会确定子元素的位置。


2657154-8682597edc5fe662.png

2657154-5e5521e9dac98e5e.png
onLayout

上面代码我们可以看出来,测量完毕我们获得上下左右四个定点位置,如果不是march,那么就设置进去上下左右四个点位置,然后掉onLayout方法,让父布局知道自己位置。

draw

View的draw可以说是最简单,也是最复杂的一个,简单是因为遵循如下几步

  • 画背景 backGround.draw(canvas)
  • 画自己(onDraw)
  • 画children(dispatchDraw)
  • 画装饰 (onDrawScrollBars)
    dispatchDraw会调用遍历子元素的onDraw方法。
    ViewGroup 有个方法 setWillNotDraw,这个方法标示 你确定不需要绘制任何内容可以设置为
    true,系统会进行优化,但是需要绘制的时候,你必须手动关闭它。当然该标示默认为false的。
    我们讲draw方法最简单也最麻烦,是因为,很多很好看的控件都需要很多绘制,所以我们接下来会讲绘制的几大常用类,以及自定义View的一些技巧方法。这篇就到这里。
2657154-93bf32395e6643b2.png
2017-10-14 08:34:16 inter_native 阅读数 210

(帧动画DrawableAnimation)(补间动画View Animation)(属性动画Property Animation)

  • View Animation: 视图动画在古老的Android版本系统中就已经提供了,只能被用来设置View的动画。

  • Drawable Animation: 这种动画(也叫Frame动画、帧动画)其实可以划分到视图动画的类别,专门用来一个一个的显示Drawable的resources,就像放幻灯片一样。

  • Property Animation: 属性动画只对Android 3.0(API 11)以上版本的Android系统才有效,这种动画可以设置给任何Object,包括那些还没有渲染到屏幕上的对象。这种动画是可扩展的,可以让你自定义任何类型和属性的动画。


   补间动画和帧动画,属性动画。

  补间动画,是指通过指定View的初末状态和变化时间、方式,对View的内容完成一系列的图形变换来实现动画效果。主要包括四种效 果:Alpha、Scale、Translate和Rotate。
    帧动画就是Frame动画,即指定每一帧的内容和停留时间,然后播放动画。
    属性动画和补间动画类似,不过是真的属性在变动,包括可视属性和其他属性。
    补间动画仅仅是可视属性在显示层面的动画,属性的实质并未改动。
2017-03-03 16:32:56 qq_30002543 阅读数 107
Android3.0(即API Level11)以前,Android仅支持2种动画:分别是Frame Animation(逐帧动画)和Tween Animation(补间动画),在3.0之后Android支持了一种新的动画系统,称为:Property Animation(属性动画)。
 
一、Frame Animation:(逐帧动画)
这个很好理解,一帧帧的播放图片,利用人眼视觉残留原理,给我们带来动画的感觉。它的原理的GIF图片、电影播放原理一样。
1.定义逐帧动画比较简单,只要在中使用子元素定义所有播放帧即可。
 
1  
 
(1) android:oneshot 设置是否仅播放一次
(2) android:drawable 设置每一帧图片
(3) android:duration 设置图片间切换间隔
 
2.习惯上把AnimationDrawable设置为ImageView的背景
android:background=@anim/frame_anim
然后我们就可以在java代码中获取AnimationDrawable对象了
AnimationDrawable anim = (AnimationDrawable)imageView.getBackground();
(需要注意的是,AnimationDrawable默认是不播放的,调用其start()方法开始播放,stop停止播放)
 
3.上面的动画文件是通过xml文件来配置的,如果你喜欢,也可以通过在java代码中创建AnimationDrawable对象,然后通过addFrame(Drawable frame, int duration)方法向动画添加帧,然后start()。。。
 
二、Tween Animation:(补间动画)
补间动画就是我们只需指定开始、结束的“关键帧“,而变化中的其他帧由系统来计算,不必自己一帧帧的去定义。
1. Android使用Animation代表抽象动画,包括四种子类:AlphaAnimation(透明度动画)、ScaleAnimation(缩放动画)、TranslateAnimation(位移动画)、RotateAnimation(透明度动画)。Android里面允许在java中创建Animation类对象,但是一般都会采用动画资源文件来定义动画,把界面与逻辑分离
 
1
2
3
4
5
6
<set android:interpolator="@android:anim/linear_interpolator" xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 定义透明度的变换 -->

<!-- 定义旋转变换 -->
<rotate android:duration="3000/" android:fromdegrees="0" android:pivotx="50%" android:pivoty="50%" android:todegrees="1800">
</rotate></alpha></set>
 
(一个set可以同时定义多个动画,一起执行。)
 
2. android:interpolator=@android:anim/linear_interpolator控制动画期间需要补入多少帧,简单来说就是控制动画速度,有些地方翻译为“插值“。Interpolator有几种实现类:LinearInterpolator、AccelerateInterpolator、AccelerateDecelerateInterpolator、CycleInterpolator、DecelerateInterpolator,具体使用可以参考官方API Demo。
 
3. 定义好anim文件后,我们可以通过AnimationUtils工具类来加载它们,加载成功后返回一个Animation。然后就可以通过View的startAnimation(anim)开始执行动画了。
 
1
2
3
4
5
6
7
Animation anim = AnimationUtils.loadAnimation(this, R.anim.anim);
//设置动画结束后保留结束状态
anim.setFillAfter(true);
//设置插值效果
anim.setInterpolator(interpolator);
//对view执行动画
view. startAnimation(anim);


 
三、Property Animation:(属性动画)
属性动画,这个是在Android 3.0中才引进的,它可以直接更改我们对象的属性。在上面提到的Tween Animation中,只是更改View的绘画效果而View的真实属性是不改变的。假设你用Tween动画将一个Button从左边移到右边,无论你怎么点击移动后的Button,他都没有反应。而当你点击移动前Button的位置时才有反应,因为Button的位置属性木有改变。而Property Animation则可以直接改变View对象的属性值,这样可以让我们少做一些处理工作,提高效率与代码的可读性。
(1)ValueAnimator:包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。应用ValueAnimator有两个步骤
1计算属性值。
2根据属性值执行相应的动作,如改变对象的某一属性。
我们的主是第二步,需要实现ValueAnimator.onUpdateListener接口,这个接口只有一个函数onAnimationUpdate(),将要改变View对象属性的事情在该接口中do。
 
1
2
3
4
5
6
animation.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//do your work
}
});
 
(2)ObjectAnimator:继承自ValueAnimator,要指定一个对象及该对象的一个属性,当属性值计算完成时自动设置为该对象的相应属性,即完成了Property Animation的全部两步操作。实际应用中一般都会用ObjectAnimator来改变某一对象的某一属性,但用ObjectAnimator有一定的限制,要想使用ObjectAnimator,应该满足以下条件:
1.对象应该有一个setter函数:set(驼峰命名法)
2如下面的例子,像ofFloat之类的工场方法,第一个参数为对象名,第二个为属性名,后面的参数为可变参数,如果values…参数只设置了一个值的话,那么会假定为目的值,属性值的变化范围为当前值到目的值,为了获得当前值,该对象要有相应属性的getter方法:get
3如果有getter方法,其应返回值类型应与相应的setter方法的参数类型一致。
 
1
2
3
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, alpha, 0f, 1f);
oa.setDuration(3000);
oa.start();
 
如果不满足上面的条件,我们只能乖乖的使用ValueAnimator来创建动画。
 
(3)Animator.AnimatorListener:可以为Animator设置动画监听,需要重写下面四个方法。
 
1
2
3
4
onAnimationStart()
onAnimationEnd()
onAnimationRepeat()
onAnimationCancel()
 
这里我们也可以实现AnimatorListenerAdapter,他的好处是可以只用定义想监听的事件而不用实现每个函数却只定义一空函数体。如下:
 
1
2
3
4
5
anim.addListener(new AnimatorListenerAdapter() {
public void on AnimationEnd(Animator animation){
//do your work
}
});

 
(4)AnimationSet:可以组合多个动画共同工作
 
1
2
3
4
5
6
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(anim1).before(anim2);
bouncer.play(anim2).with(anim3);
bouncer.play(anim2).with(anim4)
bouncer.play(anim5).after(amin2);
animatorSet.start();
 
上面的代码意思是: 首先播放anim1;同时播放anim2,anim3,anim4;最后播放anim5。
 
(5)TimeInterplator:与Tween中的interpolator类似。有以下几种
AccelerateInterpolator      加速,开始时慢中间加速
DecelerateInterpolator       减速,开始时快然后减速
AccelerateDecelerateInterolator  先加速后减速,开始结束时慢,中间加速
AnticipateInterpolator       反向 ,先向相反方向改变一段再加速播放
AnticipateOvershootInterpolator  反向加回弹,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值
BounceInterpolator        跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
CycleIinterpolator         循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
LinearInterpolator         线性,线性均匀改变
OvershottInterpolator       回弹,最后超出目的值然后缓慢改变到目的值
TimeInterpolator         一个接口,允许你自定义interpolator,以上几个都是实现了这个接口
 
(6)Keyframes:可以让我们定义除了开始和结束以外的关键帧。KeyFrame是抽象类,要通过ofInt(),ofFloat(),ofObject()获得适当的KeyFrame,然后通过PropertyValuesHolder.ofKeyframe获得PropertyValuesHolder对象,如下:
 
1
2
3
4
5
6
7
Keyframe kf0 = Keyframe.ofInt(0, 400);
Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
Keyframe kf4 = Keyframe.ofInt(0.75f, 100);
Keyframe kf3 = Keyframe.ofInt(1f, 500);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe(width, kf0, kf1, kf2, kf4, kf3);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(btn, pvhRotation);
上述代码的意思是:设置btn对象的width属性值使其:开始时 Width=400,动画开始1/4时 Width=200,动画开始1/2时 Width=400,动画开始3/4时 Width=100,动画结束时 Width=500。
 
(7)ViewPropertyAnimator:对一个View同时改变多种属性,非常推荐用这种。该类对多属性动画进行了优化,会合并一些invalidate()来减少刷新视图。而且使用起来非常简便,但是要求API LEVEL 12,即Android 3.1以上。仅需要一行代码即可完成水平、竖直移动
 
1 myView.animate().translationX(50f). translationY(100f);


 
(8)常需要改变的一些属性:
translationX,translationY: View相对于原始位置的偏移量
rotation,rotationX,rotationY: 旋转,rotation用于2D旋转角度,3D中用到后两个
scaleX,scaleY: 缩放比
x,y: View的最终坐标,是View的left,top位置加上translationX,translationY
alpha: 透明度
 
四、最后自己总结一下这三种动画的优缺点:
(1)Frame Animation(帧动画)主要用于播放一帧帧准备好的图片,类似GIF图片,优点是使用简单方便、缺点是需要事先准备好每一帧图片;
(2)Tween Animation(补间动画)仅需定义开始与结束的关键帧,而变化的中间帧由系统补上,优点是不用准备每一帧,缺点是只改变了对象绘制,而没有改变View本身属性。因此如果改变了按钮的位置,还是需要点击原来按钮所在位置才有效。

(3)Property Animation(属性动画)是3.0后推出的动画,优点是使用简单、降低实现的复杂度、直接更改对象的属性、几乎可适用于任何对象而仅非View类,缺点是需要3.0以上的API支持,限制较大!但是目前国外有个开源库,可以提供低版本支持!

注:转载的,非原创。

2017-10-27 09:59:14 inter_native 阅读数 715
Android 定位大致分为三大类:GPS定位Network定位AGPS定位。而Network又细分为WIFI定位和基站定位。下面详细讲解每种定位:

  android GPS:需要GPS硬件支持,直接和卫星交互来获取当前经纬度。

  优点:速度快、精度高、可在无网络情况下使用。

  缺点:首次连接时间长、只能在户外已经开阔地使用,设备上方有遮挡物就不行了、比较耗电。

  代码

[java] view plain copy
  1. /** 
  2.      * 通过LocationListener来获取Location信息 
  3.      */  
  4.     public static void formListenerGetLocation(){  
  5.         locationManager = (LocationManager)mActivity.getSystemService(Context.LOCATION_SERVICE);  
  6.         locationListener = new LocationListener() {  
  7.   
  8.             @Override  
  9.             public void onLocationChanged(Location location) {  
  10.                 //位置信息变化时触发  
  11.                 Log4Lsy.i(TAG, "纬度:"+location.getLatitude());  
  12.                 Log4Lsy.i(TAG, "经度:"+location.getLongitude());  
  13.                 Log4Lsy.i(TAG, "海拔:"+location.getAltitude());  
  14.                 Log4Lsy.i(TAG, "时间:"+location.getTime());  
  15.             }  
  16.   
  17.             @Override  
  18.             public void onStatusChanged(String provider, int status,Bundle extras) {  
  19.                 //GPS状态变化时触发  
  20.             }  
  21.   
  22.             @Override  
  23.             public void onProviderEnabled(String provider) {  
  24.                 //GPS禁用时触发  
  25.             }  
  26.   
  27.             @Override  
  28.             public void onProviderDisabled(String provider) {  
  29.                 //GPS开启时触发   
  30.             }  
  31.         };  
  32.         /** 
  33.          * 绑定监听 
  34.          * 参数1,设备:有GPS_PROVIDER和NETWORK_PROVIDER两种,前者是GPS,后者是GPRS以及WIFI定位 
  35.          * 参数2,位置信息更新周期.单位是毫秒 
  36.          * 参数3,位置变化最小距离:当位置距离变化超过此值时,将更新位置信息 
  37.          * 参数4,监听 
  38.          * 备注:参数2和3,如果参数3不为0,则以参数3为准;参数3为0,则通过时间来定时更新;两者为0,则随时刷新 
  39.          */  
  40.         locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 00, locationListener);  
  41.     }  
  基站定位:基站定位的方式有多种,一般手机附近的三个基站进行三角定位,由于每个基站的位置是固定的,利用电磁波在这三个基站间中转所需要时间来算出手机所在的坐标,还有一种则是,利用电磁波在这三个基站间中转所需要时间来算出手机所在的坐标;第二种则是利用获取最近的基站的信息,其中包括基站 id,location area code、mobile country code、mobile network code和信号强度,将这些数据发送到google的定位web服务里,就能拿到当前所在的位置信息。

  优点:受环境的影响情况较小,不管在室内还是人烟稀少的地方都能用,只要有基站。

  缺点: 首先需要消耗流量、其实精度没有GPS那么准确,大概在十几米到几十米之间、

  代码

[java] view plain copy
  1. /** 
  2.      * 主动获取Location,通过以下方法获取到的是最后一次定位信息。 
  3.      * 注意:Location location=new Location(LocationManager.GPS_PROVIDER)方式获取的location的各个参数值都是为0。 
  4.      */  
  5.     public static void getLocation(){  
  6.         locationManager = (LocationManager)mActivity.getSystemService(Context.LOCATION_SERVICE);  
  7.         Location location=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);  
  8.         Log4Lsy.i(TAG, "纬度:"+location.getLatitude());  
  9.         Log4Lsy.i(TAG, "经度:"+location.getLongitude());  
  10.         Log4Lsy.i(TAG, "海拔:"+location.getAltitude());  
  11.         Log4Lsy.i(TAG, "时间:"+location.getTime());  
  12.           
  13.     }  
  WIFI定位:Wifi定位是根据一个固定的WifiMAC地址,通过收集到的该Wifi热点的位置,然后访问网络上的定位服务以获得经纬度坐标。

  优点:和基站定位一样,它的优势在于收环境影响较小,只要有Wifi的地方可以使用。

  缺点:需要有wifi、精度不准。

  代码

[java] view plain copy
  1. /** 
  2.      * 通过WIFI获取定位信息 
  3.      */  
  4.     public static void fromWIFILocation(){  
  5.         //WIFI的MAC地址  
  6.         WifiManager manager = (WifiManager)mActivity.getSystemService(Context.WIFI_SERVICE);   
  7.         String wifiAddress = manager.getConnectionInfo().getBSSID();   
  8.         //根据WIFI信息定位  
  9.         DefaultHttpClient client = new DefaultHttpClient();   
  10.         HttpPost post = new HttpPost("http://www.google.com/loc/json");   
  11.         JSONObject holder = new JSONObject();  
  12.         try {  
  13.             holder.put("version" , "1.1.0");  
  14.             holder.put( "host" , "maps.google.com");   
  15.             JSONObject data;                 
  16.             JSONArray array = new JSONArray();  
  17.             if(wifiAddress!=null&&!wifiAddress.equals("")){  
  18.                 data = new JSONObject();   
  19.                 data.put("mac_address", wifiAddress);   
  20.                 data.put("signal_strength"8);   
  21.                 data.put("age"0);   
  22.                 array.put(data);   
  23.             }  
  24.             holder.put("wifi_towers",array);   
  25.             StringEntity se = new StringEntity(holder.toString());   
  26.             post.setEntity(se);  
  27.             HttpResponse resp =client.execute(post);   
  28.             int state =resp.getStatusLine().getStatusCode();   
  29.             if (state == HttpStatus.SC_OK) {  
  30.                 HttpEntity entity =resp.getEntity();   
  31.                 if (entity != null) {  
  32.                     BufferedReader br = new BufferedReader(new InputStreamReader(entity.getContent()));  
  33.                     StringBuffer sb = new StringBuffer();   
  34.                     String resute = "";  
  35.                     while ((resute =br.readLine()) != null) {                       
  36.                         sb.append(resute);                     
  37.                     }                     
  38.                     br.close();   
  39.                     data = new JSONObject(sb.toString());   
  40.                     data = (JSONObject)data.get("location");   
  41.                     Location loc = new Location(LocationManager.NETWORK_PROVIDER);  
  42.                     loc.setLatitude((Double)data.get("latitude"));                     
  43.                     loc.setLongitude((Double)data.get("longitude"));  
  44.                     //其他信息同样获取方法  
  45.                     Log4Lsy.i(TAG, "latitude ===== "+(Double)data.get("latitude"));  
  46.                     Log4Lsy.i(TAG, "longitude ===== "+(Double)data.get("longitude"));  
  47.                 }  
  48.             }  
  49.         } catch (Exception e) {  
  50.             e.printStackTrace();  
  51.         }  
  52.           
  53.     }  
关于WIFI定位,此处有一篇非常详尽的文章,大家可参考此文章:http://www.jb51.net/article/52673.htm
  AGPS定位:AssistedGPS(辅助全球卫星定位系统),是结合GSM或GPRS与传统卫星定位,利用基地台代送辅助卫星信息,以缩减GPS芯片获取卫星信号的延迟时间,受遮盖的室内也能借基地台讯号弥补,减轻GPS芯片对卫星的依赖度。和纯GPS、基地台三角定位比较,AGPS能提供范围更广、更省电、速度更快的定位服务,理想误差范围在10公尺以内,日本和美国都已经成熟运用AGPS于LBS服务(Location Based Service,基于位置的服务)。AGPS技术是一种结合了网络基站信息和GPS信息对移动台进行定位的技术,可以在GSM/GPRS、WCDMA和CDMA2000网络中使进行用。该技术需要在手机内增加GPS接收机模块,并改造手机的天线,同时要在移动网络上加建位置服务器、差分GPS基准站等设备。AGPS解决方案的优势主要体现在其定位精度上,在室外等空旷地区,其精度在正常的GPS工作环境下,可以达到10米左右,堪称目前定位精度最高的一种定位技术。该技术的另一优点为:首次捕获GPS信号的时间一般仅需几秒,不像GPS的首次捕获时间可能要1分多钟,但很明显,他的硬件要求很高,造价自然高。

  代码:AGPS的定位原理和GPS原理是差不多的,所以代码其实也是用GPS的定位方式就OK了。

最后,把我写的LocationUtil类贴上。

[java] view plain copy
  1. import java.io.BufferedReader;  
  2. import java.io.InputStreamReader;  
  3. import java.util.ArrayList;  
  4. import java.util.Iterator;  
  5. import java.util.List;  
  6.   
  7. import org.apache.http.HttpEntity;  
  8. import org.apache.http.HttpResponse;  
  9. import org.apache.http.HttpStatus;  
  10. import org.apache.http.client.methods.HttpPost;  
  11. import org.apache.http.entity.StringEntity;  
  12. import org.apache.http.impl.client.DefaultHttpClient;  
  13. import org.json.JSONArray;  
  14. import org.json.JSONObject;  
  15.   
  16. import android.annotation.SuppressLint;  
  17. import android.annotation.TargetApi;  
  18. import android.app.Activity;  
  19. import android.app.AlertDialog;  
  20. import android.content.Context;  
  21. import android.content.DialogInterface;  
  22. import android.content.Intent;  
  23. import android.location.GpsSatellite;  
  24. import android.location.GpsStatus;  
  25. import android.location.Location;  
  26. import android.location.LocationListener;  
  27. import android.location.LocationManager;  
  28. import android.net.wifi.WifiManager;  
  29. import android.os.Build;  
  30. import android.os.Bundle;  
  31. import android.provider.Settings;  
  32.   
  33. import com.function.utils.Log4Lsy;  
  34.   
  35. /** 
  36.  * Android API本身提供的定位功能,也是GPS定位。 
  37.  * GPS定位,是基于卫星定位。它受环境影响很大。并且是单向定位,也就是只有你自己知道你的地理坐标。 
  38.  * @author LuoSiye 
  39.  */  
  40. @TargetApi(Build.VERSION_CODES.CUPCAKE)  
  41. @SuppressLint("NewApi")  
  42. public class LocationUtil{  
  43.   
  44.     private static final String TAG = "LocationUtil";  
  45.       
  46.     private static LocationUtil instance;  
  47.     private static Activity mActivity;  
  48.     private static LocationManager locationManager;  
  49.     private static LocationListener locationListener;  
  50.       
  51.     public static LocationUtil getInstance(Activity activity){  
  52.         mActivity = activity;  
  53.         if(instance==null){  
  54.             instance = new LocationUtil();  
  55.         }  
  56.         locationManager = (LocationManager)mActivity.getSystemService(Context.LOCATION_SERVICE);  
  57.         return instance;  
  58.     }  
  59.       
  60.     /** 
  61.      * 判断GPS导航是否打开. 
  62.      * false:弹窗提示打开,不建议采用在后台强行开启的方式。 
  63.      * true:不做任何处理 
  64.      * @return 
  65.      */  
  66.     public static void isOpenGPS(){  
  67.           
  68.         if (!locationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER)){  
  69.             AlertDialog.Builder dialog = new AlertDialog.Builder(mActivity);  
  70.             dialog.setMessage("GPS未打开,是否打开?");  
  71.             dialog.setPositiveButton("确定"new DialogInterface.OnClickListener() {  
  72.                   
  73.                 @Override  
  74.                 public void onClick(DialogInterface dialog, int which) {  
  75.                     Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);  
  76.                     // 设置完成后返回到原来的界面  
  77.                     mActivity.startActivityForResult(intent, 0);   
  78.                 }  
  79.             });  
  80.             dialog.setNegativeButton("取消"new DialogInterface.OnClickListener() {  
  81.                   
  82.                 @Override  
  83.                 public void onClick(DialogInterface dialog, int which) {  
  84.                     dialog.dismiss();  
  85.                 }  
  86.             });  
  87.             dialog.show();  
  88.         }  
  89.     }  
  90.   
  91.     /** 
  92.      * 通过LocationListener来获取Location信息 
  93.      */  
  94.     public static void formListenerGetLocation(){  
  95.           
  96.         locationListener = new LocationListener() {  
  97.   
  98.             @Override  
  99.             public void onLocationChanged(Location location) {  
  100.                 //位置信息变化时触发  
  101.                 Log4Lsy.i(TAG, "纬度:"+location.getLatitude());  
  102.                 Log4Lsy.i(TAG, "经度:"+location.getLongitude());  
  103.                 Log4Lsy.i(TAG, "海拔:"+location.getAltitude());  
  104.                 Log4Lsy.i(TAG, "时间:"+location.getTime());  
  105.             }  
  106.   
  107.             @Override  
  108.             public void onStatusChanged(String provider, int status,Bundle extras) {  
  109.                 //GPS状态变化时触发  
  110.             }  
  111.   
  112.             @Override  
  113.             public void onProviderEnabled(String provider) {  
  114.                 //GPS禁用时触发  
  115.             }  
  116.   
  117.             @Override  
  118.             public void onProviderDisabled(String provider) {  
  119.                 //GPS开启时触发   
  120.             }  
  121.         };  
  122.         /** 
  123.          * 绑定监听 
  124.          * 参数1,设备:有GPS_PROVIDER和NETWORK_PROVIDER两种,前者是GPS,后者是GPRS以及WIFI定位 
  125.          * 参数2,位置信息更新周期.单位是毫秒 
  126.          * 参数3,位置变化最小距离:当位置距离变化超过此值时,将更新位置信息 
  127.          * 参数4,监听 
  128.          * 备注:参数2和3,如果参数3不为0,则以参数3为准;参数3为0,则通过时间来定时更新;两者为0,则随时刷新 
  129.          */  
  130.         locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 00, locationListener);  
  131.     }  
  132.       
  133.     /** 
  134.      * 主动获取Location,通过以下方法获取到的是最后一次定位信息。 
  135.      * 注意:Location location=new Location(LocationManager.GPS_PROVIDER)方式获取的location的各个参数值都是为0。 
  136.      */  
  137.     public static void getLocation(){  
  138.           
  139.         Location location=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);  
  140.         Log4Lsy.i(TAG, "纬度:"+location.getLatitude());  
  141.         Log4Lsy.i(TAG, "经度:"+location.getLongitude());  
  142.         Log4Lsy.i(TAG, "海拔:"+location.getAltitude());  
  143.         Log4Lsy.i(TAG, "时间:"+location.getTime());  
  144.           
  145.     }  
  146.       
  147.     /** 
  148.      * 获取GPS状态监听,包括GPS启动、停止、第一次定位、卫星变化等事件。 
  149.      */  
  150.     public static void getStatusListener(){  
  151.           
  152.         GpsStatus.Listener listener = new GpsStatus.Listener(){  
  153.   
  154.             @Override  
  155.             public void onGpsStatusChanged(int event) {  
  156.                 if(event==GpsStatus.GPS_EVENT_FIRST_FIX){  
  157.                     //第一次定位  
  158.                 }else if(event==GpsStatus.GPS_EVENT_SATELLITE_STATUS){  
  159.                     //卫星状态改变  
  160.                     GpsStatus gpsStauts= locationManager.getGpsStatus(null); // 取当前状态  
  161.                     int maxSatellites = gpsStauts.getMaxSatellites(); //获取卫星颗数的默认最大值  
  162.                     Iterator<GpsSatellite> it = gpsStauts.getSatellites().iterator();//创建一个迭代器保存所有卫星  
  163.                     int count = 0;  
  164.                     while (it.hasNext() && count <= maxSatellites) {      
  165.                         count++;     
  166.                         GpsSatellite s = it.next();    
  167.                     }  
  168.                     Log4Lsy.i(TAG, "搜索到:"+count+"颗卫星");  
  169.                 }else if(event==GpsStatus.GPS_EVENT_STARTED){  
  170.                     //定位启动  
  171.                 }else if(event==GpsStatus.GPS_EVENT_STOPPED){  
  172.                     //定位结束  
  173.                 }  
  174.             }  
  175.         };  
  176.         //绑定  
  177.         locationManager.addGpsStatusListener(listener);   
  178.     }  
  179.       
  180.     /** 
  181.      * 获取所有卫星状态 
  182.      * @return 
  183.      */  
  184.     public static List<GpsSatellite> getGpsStatus(){  
  185.         List<GpsSatellite> result = new ArrayList<GpsSatellite>();  
  186.         GpsStatus gpsStatus = locationManager.getGpsStatus(null); // 取当前状态  
  187.         //获取默认最大卫星数  
  188.         int maxSatellites = gpsStatus.getMaxSatellites();  
  189.         //获取第一次定位时间(启动到第一次定位)  
  190.         int costTime=gpsStatus.getTimeToFirstFix();  
  191.         Log4Lsy.i(TAG, "第一次定位时间:"+costTime);  
  192.         //获取卫星  
  193.         Iterable<GpsSatellite> iterable=gpsStatus.getSatellites();  
  194.         //一般再次转换成Iterator  
  195.         Iterator<GpsSatellite> itrator=iterable.iterator();  
  196.         int count = 0;  
  197.         while (itrator.hasNext() && count <= maxSatellites){  
  198.             count++;  
  199.             GpsSatellite s = itrator.next();  
  200.             result.add(s);  
  201.         }  
  202.         return result;  
  203.     }  
  204.       
  205.     /** 
  206.      * 某一个卫星的信息. 
  207.      * @param gpssatellite 
  208.      */  
  209.     public static void getGpsStatelliteInfo(GpsSatellite gpssatellite){  
  210.           
  211.         //卫星的方位角,浮点型数据    
  212.         Log4Lsy.i(TAG, "卫星的方位角:"+gpssatellite.getAzimuth());  
  213.         //卫星的高度,浮点型数据    
  214.         Log4Lsy.i(TAG, "卫星的高度:"+gpssatellite.getElevation());  
  215.         //卫星的伪随机噪声码,整形数据    
  216.         Log4Lsy.i(TAG, "卫星的伪随机噪声码:"+gpssatellite.getPrn());  
  217.         //卫星的信噪比,浮点型数据    
  218.         Log4Lsy.i(TAG, "卫星的信噪比:"+gpssatellite.getSnr());  
  219.         //卫星是否有年历表,布尔型数据    
  220.         Log4Lsy.i(TAG, "卫星是否有年历表:"+gpssatellite.hasAlmanac());  
  221.         //卫星是否有星历表,布尔型数据    
  222.         Log4Lsy.i(TAG, "卫星是否有星历表:"+gpssatellite.hasEphemeris());  
  223.         //卫星是否被用于近期的GPS修正计算    
  224.         Log4Lsy.i(TAG, "卫星是否被用于近期的GPS修正计算:"+gpssatellite.hasAlmanac());  
  225.     }  
  226.       
  227.     /** 
  228.      * 通过WIFI获取定位信息 
  229.      */  
  230.     public static void fromWIFILocation(){  
  231.         //WIFI的MAC地址  
  232.         WifiManager manager = (WifiManager)mActivity.getSystemService(Context.WIFI_SERVICE);   
  233.         String wifiAddress = manager.getConnectionInfo().getBSSID();   
  234.         //根据WIFI信息定位  
  235.         DefaultHttpClient client = new DefaultHttpClient();   
  236.         HttpPost post = new HttpPost("http://www.google.com/loc/json");   
  237.         JSONObject holder = new JSONObject();  
  238.         try {  
  239.             holder.put("version" , "1.1.0");  
  240.             holder.put( "host" , "maps.google.com");   
  241.             JSONObject data;                 
  242.             JSONArray array = new JSONArray();  
  243.             if(wifiAddress!=null&&!wifiAddress.equals("")){  
  244.                 data = new JSONObject();   
  245.                 data.put("mac_address", wifiAddress);   
  246.                 data.put("signal_strength"8);   
  247.                 data.put("age"0);   
  248.                 array.put(data);   
  249.             }  
  250.             holder.put("wifi_towers",array);   
  251.             StringEntity se = new StringEntity(holder.toString());   
  252.             post.setEntity(se);  
  253.             HttpResponse resp =client.execute(post);   
  254.             int state =resp.getStatusLine().getStatusCode();   
  255.             if (state == HttpStatus.SC_OK) {  
  256.                 HttpEntity entity =resp.getEntity();   
  257.                 if (entity != null) {  
  258.                     BufferedReader br = new BufferedReader(new InputStreamReader(entity.getContent()));  
  259.                     StringBuffer sb = new StringBuffer();   
  260.                     String resute = "";  
  261.                     while ((resute =br.readLine()) != null) {                       
  262.                         sb.append(resute);                     
  263.                     }                     
  264.                     br.close();   
  265.                     data = new JSONObject(sb.toString());   
  266.                     data = (JSONObject)data.get("location");   
  267.                     Location loc = new Location(LocationManager.NETWORK_PROVIDER);  
  268.                     loc.setLatitude((Double)data.get("latitude"));                     
  269.                     loc.setLongitude((Double)data.get("longitude"));  
  270.                     //其他信息同样获取方法  
  271.                     Log4Lsy.i(TAG, "latitude ===== "+(Double)data.get("latitude"));  
  272.                     Log4Lsy.i(TAG, "longitude ===== "+(Double)data.get("longitude"));  
  273.                 }  
  274.             }  
  275.         } catch (Exception e) {  
  276.             e.printStackTrace();  
  277.         }  
  278.           
  279.     }  
  280. }  

android 推送

阅读数 56

千万级并发手机推送系统建设http://news.eoe.cn/industry/2012/1213/10759.html主要介绍个推:http://www.igetui.com/,目前新浪客户端的推送就是使用的这个。还有一个叫极光推送。...

博文 来自: iteye_19606

android 推送

阅读数 65

当进程杀死时候就接受不到推送过来的消息。小米和华为手机属于那种深度定制安卓系统,需要用户的操作(自启动、白名单等)才能够实现应用“保活”的目的。小米【MIUI】  自启动管理:需要把应用加到【自启动管理】列表,否则杀进程或重新开机后进程无法开启  通知栏设置:应用默认都是显示通知栏通知,如果关闭,则收到通知也不会提示  网络助手:可以手动禁止已安装的第三方程序访问2G/3G和WIF

博文 来自: xianglongjifei

【进阶android】ListView源码分析——布局三大方法

阅读数 721

视图从初始化到完全展示到屏幕之上,这段时间里,还有许多工作要做;总体而言,这些工作可用分为三大步骤;而这三大步骤便是View类的三大布局方法onMeasure、onLayout以及onDraw,三个方法分别表示对视图进行测量、布局及绘制。   ListView是一个视图,当然也会重写这三个主要的方法;同时,这三个方法也完成了ListView在展示到屏幕之前,所需要完成的绝大多数初始化工作。

博文 来自: xiaogutou1

android 的推送

阅读数 930

先来将一下ios的推送:iOS在系统级别有一个推送服务程序使用5223端口。使用这个端口的协议源于Jabber后来发展为XMPP,被用于Gtalk等IM软件中。所以,iOS的推送,可以不严谨的理解为:苹果服务器朝手机后台挂的一个IM服务程序发送的消息。然后,系统根据该IM消息识别告诉哪个Apps具体发生了什么事。然后,系统分别通知这些

博文 来自: dangxw_

android 推送

阅读数 308

android推送网站

博文 来自: wwwyuanliang10000
没有更多推荐了,返回首页