Android ServiceConnection

绑定到一个Service

应用组件 (客户端)可以调用bindService()绑定到一个service.

Android系统之后调用service的onBind()方法,它返回一个用来与service交互的IBinder,绑定是异步的.

bindService()会立即返回,它不会返回IBinder给客户端.

要接收IBinder,客户端必须创建一个ServiceConnection的实例并传给bindService().

ServiceConnection包含一个回调方法,系统调用这个方法来传递要返回的IBinder.

注:只有activities,services,和contentproviders可以绑定到一个service,你不能从一个broadcastreceiver绑定到service.

所以,从你的客户端绑定到一个service,你必须:

1.实现ServiceConnection

你的实现必须重写两个回调方法:

onServiceConnected()

系统调用这个来传送在service的onBind()中返回的IBinder.

OnServiceDisconnected()

Android系统在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了.当客户端解除绑定时,这个方法不会被调用.

2.调用bindService(),传给它ServiceConnection的实现


3.当系统调用你的onServiceConnected()方法时,你就可以使用接口定义的方法们开始调用service了


4.要与service断开连接,调用unbindService()

当你的客户端被销毁,它将从service解除绑定,但是你必须总是在你完成与service的交互时或当你的activity暂停或是service在不被使用时可以关闭此两种情况下解除绑定. (下面会讨论更多在适当的时候绑定和解除绑定的问题.)

下面是"派生Binder类"中创建的代码片段,它把客户端连接到了service.

所需要做的就是把返回的IBinder强制转换(向下转型)到LocalBinder类并且请求LocalService实例:

private ServiceConnection mConnection = new ServiceConnection() {
    // 当与service的连接建立后(bindService)被调用  
    public void onServiceConnected(ComponentName className, IBinder service) {
        // Because we have bound to an explicit  
        // service that is running in our own process, we can  
        // cast its IBinder to a concrete class and directly access it.  
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }
    // 当与service的连接意外断开时被调用  
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "onServiceDisconnected");
        mBound = false;
    }
};

使用这个ServiceConnection,客户端可以绑定到一个service,通过把它传给bindService().例如:

Intentintent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

第一个bindService()的参数是一个明确指定了要绑定的service的Intent.

第二个参数是ServiceConnection对象.

第三个参数是一个标志,它表明绑定中的操作.它一般应是BIND_AUTO_CREATE,这样就会在service不存在时创建一个.其它可选的值是BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,

不想指定时设为0即可.

补充事项下面是一些关于绑定到service的重要事项:

你总是需要捕获DeadObjectException异常.它会在连接被打断时抛出.这是被远程方法抛出的唯一异常.

对象引用计数是跨进程的作用的.

你应该在客户端的生命期内使绑定和解除绑定配对进行,例如:

如果你需要在你的activity可见时与service交互,你应该在onStart()绑定并在onStop()中解除绑定.

如果你想让你的activity即使在它停止时也能接收回应,那么你可以在onCreate()中绑定并在onDestroy()中解除绑定.

注意这意味着你的activity需要使用在自己整个运行期间使用service(即使位于后台),所以如果service在另一个进程中,那么你增加了这个进程的负担而使它变得更容易被系统杀掉.

注:你一般不应该在你的activity的onResume()和onPause()中绑定和解除绑定到service,因为这些回调方法,出现在每个生命期变化中,并且你需要使发生在这些变化中的处理最小化.还有,如果你应用中的多个activity绑定到同一个service,并且有一个变化发生在其中两个activity之间,service可能在当前activity解除绑定 (pause中)和下一个绑定前 (rusume中)被销毁又重建.

管理BoundService的生命期  当一个service的所有客户端都解除绑定,Android系统就销毁它 (除非它是从onStartCommand()启动).如果你的service是一个纯boundservice,你不需管理它的生命期—Android系统会为你管理它.

然而,如果你选择了实现onStartCommand()回调方法,那么你必须明确地停止service,因为service现在被认为是"开始的".在此情况下,service会一直运行,直到service使用stopSelf()停止它自己或另外的组件调用了stopService()停止了它,不管是否有客户端绑定了它.

另外,如果你的service已经启动并且接受绑定,那么当系统调用你的onUnbind()方法,你可以选择返回true表示你想在客户端下一次绑定到service时接受一个对onRebind()的调用 (而不是一个对onBind()的调用).onRebind()返回void,但是客户端依然会在它的onServiceConnected()回调中接收到IBinder.下图演示了这种生命其的逻辑:

图1.一个已开始并已绑定的service的生命期

1332714811_8009.png

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销毁而销毁了。

java中的匿名内部类总结

匿名内部类也就是没有名字的内部类

正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写

但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口

实例1 : 不使用匿名内部类来实现抽象方法

abstract class Person {
    public abstract void eat();
}

class Child extends Person {
    public void eat() {
        System.out.println("eat something");
    }
}

public class Demo {
    public static void main(String[] args) {
        Person p = new Child();
        p.eat();
    }
}

运行结果:eat something

可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用

但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?

这个时候就引入了匿名内部类

实例2:匿名内部类的基本实现

abstract class Person {
    public abstract void eat();
}

public class Demo {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

运行结果:eat something

可以看到,我们直接将抽象类Person中的方法在大括号中实现了

这样便可以省略一个类的书写

并且,匿名内部类还能用于接口上

实例3:在接口上使用匿名内部类

interface Person {
    public void eat();
}
public class Demo {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

运行结果:eat something

由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现

最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口

实例4:Thread类的匿名内部类实现

public class Demo {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        t.start();
    }
}

运行结果:1 2 3 4 5

实例5:Runnable接口的匿名内部类实现

public class Demo {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        Thread t = new Thread(r);
        t.start();
    }
}

向下转型

在学习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);  
    }   
}

svn: E170001: Authorization failed

出现该问题基本都是三个配置文件的问题,下面把这个文件列出来。

svnserve.conf:

[general]

anon-access = read

auth-access = write

password-db = passwd

authz-db = authz

passwd:

[users]

harry = harryssecret

authz:

[groups]

[/]

harry = rw

出现authorization failed异常,一般都是authz文件里,用户组或者用户权限没有配置好,只要设置[/]就可以,代表根目录下所有的资源,如果要限定资源,可以加上子目录即可。

安卓學習筆記

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

Python3.5 用 pip 安装lxml

pip 安装不了

 

最后在知乎上找到答案

 

作者:深海鱼
链接:http://www.zhihu.com/question/26857761/answer/69754633
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

1. 安装wheel,命令行运行:pip install wheel
2.在这里下载对应的.whl文件,注意别改文件名!http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxmlCtrl + F,输入lxml,找到下面这段Lxml, a binding for the libxml2 and libxslt libraries.lxml‑3.4.4‑cp27‑none‑win32.whllxml‑3.4.4‑cp27‑none‑win_amd64.whllxml‑3.4.4‑cp33‑none‑win32.whllxml‑3.4.4‑cp33‑none‑win_amd64.whllxml‑3.4.4‑cp34‑none‑win32.whllxml‑3.4.4‑cp34‑none‑win_amd64.whllxml‑3.4.4‑cp35‑none‑win32.whllxml‑3.4.4‑cp35‑none‑win_amd64.whlcp后面是Python的版本号,27表示2.7,根据你的Python版本选择下载。3. 进入.whl所在的文件夹,执行命令即可完成安装pip install 带后缀的完整文件名