Service 两种启动方式

1.Context.startService()方式启动

Context.startService()方式的生命周期:

启动时,startService–>onCreate()–>onStart()

停止时,stopService– > onDestroy()

如果调用者直接退出而没有停止Service,

则Service会一直在后台运行Context.startService()方法启动服务。

在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。

如果调用startService()方法前服务已经被创建,

多次调用startService()方法并不会导致多次创建服务,

但会导致多次调用onStart()方法。

采用startService()方法启动的服务,

只能调用Context.stopService()方法结束服务,

服务结束时会调用onDestroy()方法。

2.Context.bindService()方式启动


Context.bindService()方式的生命周期:绑定时,

bindService->onCreate()–>onBind()调用者退出了,即解绑定时,

Srevice就会unbindService–>onUnbind()–>onDestory() 

Context.bindService()方式启动Service的方法:

绑定Service需要三个参数:bindService(intent, conn, Service.BIND_AUTO_CREATE);

第一个:Intent对象

第二个:ServiceConnection对象,创建该对象要实现它的onServiceConnected()和onServiceDisconnected()来判断连接成功或者是断开连接

第三个:如何创建Service,一般指定绑定的时候自动创建附代码

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.dada.test.BindService.MyBinder;
public class TestActivity extends Activity {
    private boolean flag;
    private static final String TAG = "TestActivity";
    /** Called when the activity is first created. */
    @Override public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button btnStart = (Button) findViewById(R.id.btnStart);
        Button btnStop = (Button) findViewById(R.id.btnStop);
        btnStart.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {
                //启动service 方式2  
                bindService();
            }
        });
        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                //停止service 方式2  
                unBindService();
            }
        });
    }
    //启动service 方式2  
    //  
    private void bindService() {
        Intent intent = new Intent(TestActivity.this, BindService.class);
        Log.i(TAG, "bindService()");
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }
    private void unBindService() {
        Log.i(TAG, "unBindService() start....");
        if (flag == true) {
            Log.i(TAG, "unBindService() flag");
            unbindService(conn);
            flag = false;
        }
    }
    private ServiceConnection conn = new ServiceConnection() {
        @Override public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub  
            Log.i(TAG, "onServiceDisconnected()");
        }
        @Override public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub  
            Log.i(TAG, "onServiceConnected()");
            MyBinder binder = (MyBinder) service;
            BindService bindService = binder.getService1();
            bindService.MyMethod();
            flag = true;
        }
    };
}

service:

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class BindService extends Service {
    private static final String TAG = "BindService";
    private MyBinder myBinder = new MyBinder();
    public void MyMethod() {
        Log.i(TAG, "BindService-->MyMethod()");
    }
    
    @Override public IBinder onBind(Intent intent) {
        Log.i(TAG, "BindService-->onBind()");
        return myBinder;
    }
    
    public class MyBinder extends Binder {
        public BindService getService1() {
            return BindService.this;
        }
    }
    
    @Override public void onCreate() {
        Log.i(TAG, "BindService-->onCreate()");
        super.onCreate();
    }
    @Override public void onStart(Intent intent, int startId) {
        Log.i(TAG, "BindService-->onStart()");
        super.onStart(intent, startId);
    }
    @Override public void onDestroy() {
        Log.i(TAG, "BindService-->onDestroy()");
        super.onDestroy();
    }
    @Override public boolean onUnbind(Intent intent) {
        Log.i(TAG, "BindService-->onUnbind()");
        return super.onUnbind(intent);
    }
}

运行日志点击启动

点击停止

没有打出onServiceDisconnected的日志的原因:

注:SDK上是这么说的:This is called when the connection with the service has been unexpectedly disconnected–that is,

its process crashed.Because it is running in our same process,

we should never see this happen.

所以说,只有在service因异常而断开连接的时候,这个方法才会用到

其他

由于Service的onStart()方法只有在startService()启动Service的情况下才调用,故使用onStart()的时候要注意这点。

与Service通信并且让它持续运行如果我们想保持和Service的通信,又不想让Service随着Activity退出而退出呢?

你可以先startService()然后再bindService()。

当你不需要绑定的时候就执行unbindService()方法,执行这个方法只会触发Service的onUnbind()而不会把这个Service销毁。

这样就可以既保持和Service的通信,也不会随着Activity销毁而销毁了。

向下转型

在学习Android的时候 书里提到了向下转型

对java不熟悉的我又要补课了

这篇博客就是讲向下转型的,那我们就来学习下向下转型,了解下这种特性的意义和使用场景

新建一个电子产品接口,如下:

public interface Electronics{

}

很简单,什么方法都没有。

新建一个Thinkpad笔记本类,并实现电子产品接口:

public class Thinkpad implements Electronics {

    //Thinkpad引导方法
    public void boot() {
        System.out.println("welcome,I am Thinkpad");
    }

    //使用Thinkpad编程  
    public void program() {
        System.out.println("using Thinkpad program");
    }

}

新建一个Mouse鼠标类,并实现电子产品接口:

public class Mouse implements Electronics{

    //鼠标移动
    public void move(){
        System.out.println("move the mouse");       
    }    //鼠标点击  
    public void onClick(){
        System.out.println("a click of the mouse");
    }

}

新建一个Keyboard键盘类,并实现电子产品接口:

public class Keyboard implements Electronics{

    //使用键盘输入    
    public void input(){
        System.out.println("using Keyboard input");
    }

}

这里子类比较多,是为了更好的理解。每个类的方法的逻辑实现也很简单。打印了一行信息

接下来,我们想象一个情景:我们去商城买电子产品,电子产品很多吧,比如笔记本电脑,鼠标,键盘,步步高点读机哪里不会点哪里,我们用的手机,等等,这些都属于电子产品。

电子产品是抽象的。

好,那么我们决定买一台Thinkpad,一个鼠标和一个键盘。

这时,我们需要一个购物车来装这些电子产品吧。

我们可以添加进购物车,然后通过购物车还能知道存放的电子产品数量,能拿到对应的电子产品。

那么,一个购物车类就出来了,如下:

import java.util.ArrayList;
import java.util.List;

public class ShopCar {

    private List < Electronics > mlist = new ArrayList < Electronics > ();

    public void add(Electronics electronics) {

        mlist.add(electronics);

    }

    public int getSize() {

        return mlist.size();
    }

    public Electronics getListItem(int position) {

        return mlist.get(position);

    }

}

List集合是用来存放电子产品的,add方法用来添加电子产品到购物车,getSize方法用来获取存放的电子产品数量,getListItem方法用来获取相应的电子产品。

可以看到List < Electronics > 用了泛型的知识,至于为什么要用泛型?

这个不做介绍了,泛型很重要的。

而我觉得比较疑惑的是为什么是放Electronics的泛型,而不是放Thinkpad,Mouse,Keyboard,Phone等?

那么如果是List < Thinkpad > ,肯定是放不进鼠标Mouse的吧,难道要生成3个集合?

这里是定义了3个电子产品类,但是我如果有100种电子产品呢,要定义100个集合 ? 

这太可怕了。

所以之前,我们写了一个Electronics接口,提供了一个Electronics的标准,然后让每一个Electronics子类都去实现这个接口。

实际上这里又涉及到了向上转型的知识点,我们虽然在add方法将子类实例传了进来存放,但子类实例在传进去的过程中也进行了向上转型所以,此时购物车里存放的子类实例对象,由于向上转型成Electronics,已经丢失了子类独有的方法,以上述例子来分析,Thinkpad实例就是丢失了boot()和program()这两个方法,而Mouse实例就是丢失了move()和onClick()这两个方法

但是实际使用Thinkpad或Mouse或Keyboard时,这种情况肯定不是我们想要的

接着我们写一个测试类Test去测试购物车里的电子产品。

测试类Test如下:

public class Test {

    public static final int THINKPAD = 0;
    public static final int MOUSE = 1;
    public static final int KEYBOARD = 2;

    public static void main(String[] args) {

        //添加进购物车
        ShopCar shopcar = new ShopCar();
        shopcar.add(new Thinkpad());
        shopcar.add(new Mouse());
        shopcar.add(new Keyboard());

        //获取大小
        System.out.println("购物车存放的电子产品数量为 ——> " + shopcar.getSize());

        //开始测试thinkpad电脑
        Thinkpad thinkpad = (Thinkpad) shopcar.getListItem(THINKPAD);
        thinkpad.boot();
        thinkpad.program();

        System.out.println("-------------------");

        //开始测试Mouse鼠标
        Mouse mouse = (Mouse) shopcar.getListItem(MOUSE);
        mouse.move();
        mouse.onClick();

        System.out.println("-------------------");

        //开始测试Keyboard键盘
        Keyboard keyboard = (Keyboard) shopcar.getListItem(KEYBOARD);
        keyboard.input();
    }

}

运行截图:

20161022214436745.png

举个例子分析就好

//开始测试thinkpad电脑
Thinkpad thinkpad = (Thinkpad)shopcar.getListItem(THINKPAD);
thinkpad.boot();
thinkpad.program();

shopcar.getListItem(THINKPAD)这句代码是获取到Electronics类型的实例。不是Thinkpad的实例

通过向下转型,赋值给子类引用

Thinkpad thinkpad = (Thinkpad) shopcar.getListItem(THINKPAD);

这样子类实例又重新获得了因为向上转型而丢失的方法(boot和program)

总结一下吧,很多时候,我们需要把很多种类的实例对象,全部扔到一个集合。(这句话很重要)

在这个例子里就是把Thinkpad笔记本,Mouse鼠标,KeyBoard键盘等实例对象,全部扔到一个Shopcar购物车集合。

但是肯定不可能给他们每个种类都用一个独立的集合去存放吧,这个时候我们应该寻找到一个标准,接口就是一个标准。这些都是各种电子产品,抽象成电子产品。

然后一个Electronics接口就出来了。

在回到刚才,我们把很多种类的实例对象全部扔到一个集合。

或许这样比较好理解:把很多种类的子类实例对象全部扔到存放父类实例的集合。

经过了这个过程,子类实例已经赋值给了父类引用(即完成了向上转型),但很遗憾的丢失了子类扩展的方法。

很好的是Java语言有个向下转型的特性,让我们可以重新获得丢失的方法,即强转回子类所以我们需要用到子类实例的时候,就从那个父类集合里拿出来向下转型就可以了,一样可以使用子类实例对象……

我在搜索java向下转型的意义时,得到一个比较好的答案是这样的:最大的用处是java的泛型编程,用处很大,Java的集合类都是这样的。

而在Android开发中,我们在Layout文件夹,用xml写的控件。为什么能在Activity等组件中通过findViewById()方法找到呢?

为什么findViewById(R.id.textview)方法传入TextView的id后,还要转型为TextView呢?

这就是Java向下转型的一个应用。

public IBinder onBind(Intent intent) { 关于此处的IBinder

在Android中Service的启动方式有两种,第一种是startService,第二种是bindService. 这里问的是第二种方法,生命周期是这样的:

bindSerivce->onCreate->onBind->running->onUnbind->onDestroy. 
由字面意思可以看出来onBind方法就是当试图绑定服务时做的事,
作用一般情况下主要是返回IBinder对象,
为后面服务成功绑定时的操作做准备,
也可以做一些服务初始化之类的事。
如果用过bindService就会知道这个方法里的第二个参数是一个ServiceConnection的对象,
在使用这个对象的时候需要重写两个方法
onServiceConnected(ComponentName name, IBinder service) 
和 
onServiceDisconnected(ComponentName name). 

其中onServiceConnected方法参数中的service就是你上面所说的返回的IBinder的对象,
,
说明服务成功绑定,而在这个方法里面你可以对服务中的一些数据进行初始化控制等操作,
实现Activity与Service之间简单的交互。

参照网上资料把Service的两种启动方式所涉及到的知识点梳理一遍,
然后再编程调试,
可以加深对这一部分知识的理解。

android AsyncTask

最近用到的 AsyncTask记录一下

AsyncTask和Handler对比

1 ) AsyncTask实现的原理,和适用的优缺点

AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.

使用的优点:

l  简单,快捷

l  过程可控

       

使用的缺点:

l  在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

2 )Handler异步实现的原理和适用的优缺点

在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)àthread(子线程)运行并生成Message-àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。

使用的优点:

l  结构清晰,功能定义明确

l  对于多个后台任务时,简单,清晰

   

使用的缺点:

l  在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)

 

AsyncTask介绍

Android的AsyncTask比Handler更轻量级一些,适用于简单的异步处理。

首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。

 

Android为了降低这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。

AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个)。

 

AsyncTask定义了三种泛型类型 Params,Progress和Result。

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。

  • Progress 后台任务执行的百分比。

  • Result 后台执行任务最终返回的结果,比如String。

使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法:

  • doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。

  • onPostExecute(Result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回

有必要的话你还得重写以下这三个方法,但不是必须的:

  • onProgressUpdate(Progress…)   可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。

  • onPreExecute()        这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。

  • onCancelled()             用户调用取消时,要做的操作

使用AsyncTask类,以下是几条必须遵守的准则:

  • Task的实例必须在UI thread中创建;

  • execute方法必须在UI thread中调用;

  • 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法;

  • 该task只能被执行一次,否则多次调用时将会出现异常;

一个超简单的理解 AsyncTask 的例子:

main.xml

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    >  
    <TextView    
    android:id="@+id/textView01"  
    android:layout_width="fill_parent"   
    android:layout_height="wrap_content"   
    />  
   <ProgressBar   
   android:id="@+id/progressBar02"  
    android:layout_width="fill_parent"   
    android:layout_height="wrap_content"   
    style="?android:attr/progressBarStyleHorizontal"   
    />  
    <Button  
    android:id="@+id/button03"  
    android:layout_width="fill_parent"   
    android:layout_height="wrap_content"   
    android:text="更新progressbar"  
    />  
</LinearLayout>

MainActivity.java

package vic.wong.main;  
  
import android.app.Activity;  
import android.os.Bundle;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
import android.widget.ProgressBar;  
import android.widget.TextView;  
  
public class MainActivity extends Activity {  
    private Button button;  
    private ProgressBar progressBar;  
    private TextView textView;  
      
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
          
        button = (Button)findViewById(R.id.button03);  
        progressBar = (ProgressBar)findViewById(R.id.progressBar02);  
        textView = (TextView)findViewById(R.id.textView01);  
          
        button.setOnClickListener(new OnClickListener() {  
              
            @Override  
            public void onClick(View v) {  
                ProgressBarAsyncTask asyncTask = new ProgressBarAsyncTask(textView, progressBar);  
                asyncTask.execute(1000);  
            }  
        });  
    }  
}

NetOperator.java

package vic.wong.main;  
  
  
//模拟网络环境  
public class NetOperator {  
      
    public void operator(){  
        try {  
            //休眠1秒  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
    }  
  
}

ProgressBarAsyncTask .java 

package vic.wong.main;  
import android.os.AsyncTask;  
import android.widget.ProgressBar;  
import android.widget.TextView;  
  
/**  
 * 生成该类的对象,并调用execute方法之后  
 * 首先执行的是onProExecute方法  
 * 其次执行doInBackgroup方法  
 *  
 */  
public class ProgressBarAsyncTask extends AsyncTask<Integer, Integer, String> {  
  
    private TextView textView;  
    private ProgressBar progressBar;  
      
      
    public ProgressBarAsyncTask(TextView textView, ProgressBar progressBar) {  
        super();  
        this.textView = textView;  
        this.progressBar = progressBar;  
    }  
  
  
    /**  
     * 这里的Integer参数对应AsyncTask中的第一个参数   
     * 这里的String返回值对应AsyncTask的第三个参数  
     * 该方法并不运行在UI线程当中,主要用于异步操作,所有在该方法中不能对UI当中的空间进行设置和修改  
     * 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作  
     */  
    @Override  
    protected String doInBackground(Integer... params) {  
        NetOperator netOperator = new NetOperator();  
        int i = 0;  
        for (i = 10; i <= 100; i+=10) {  
            netOperator.operator();  
            publishProgress(i);  
        }  
        return i + params[0].intValue() + "";  
    }  
  
  
    /**  
     * 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)  
     * 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置  
     */  
    @Override  
    protected void onPostExecute(String result) {  
        textView.setText("异步操作执行结束" + result);  
    }  
  
  
    //该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置  
    @Override  
    protected void onPreExecute() {  
        textView.setText("开始执行异步线程");  
    }  
  
  
    /**  
     * 这里的Intege参数对应AsyncTask中的第二个参数  
     * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行  
     * onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作  
     */  
    @Override  
    protected void onProgressUpdate(Integer... values) {  
        int vlaue = values[0];  
        progressBar.setProgress(vlaue);  
    }   
}

安卓6.0下验证权限

// 需要验证的权限
int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.CALL_PHONE);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
// 弹窗询问 ,让用户自己判断
    requestPermissions(new String[]{Manifest.permission.CALL_PHONE},
    REQUEST_CODE_ASK_PERMISSIONS);
    return;
}

安卓學習筆記

Android Studio 打包
http://www.open-open.com/lib/view/open1441896025274.html

单元测试

  1. 定义一个类集成AndroidTestCase

  2. 在清单文件配置users-library和instrumentation

blob.png

blob.png

3.或者可以自己手动创建一个安卓测试工程,会自动配置好

Andriod Studio 把局部变量变成全局变量的快捷键是Ctrl + Alt + F 和eclips上面的功能相同 很好用

Android studio 中的file explorer

http://blog.csdn.net/baduspace/article/details/43735109