您的位置:首页 > 运维架构

IntentService,(Looper,Message,Handler)三者之间的关系,AsyncTask,

2015-09-09 21:28 447 查看

IntentService

IntentService与service的最大的区别就是IntentService可以进行耗时操作,因为它自带了一个线程,记住只有一个线程。

在IntentService中有一个队列的概念,即在第一次启动IntentService,并在onHandleIntent中执行的时候,再第二次次启动IntentService,第二次的操作不会立刻执行,而是先将其放在队列中,当第一次运行完时,再执行第二次操作。这与Service是不一样的,当第一次还未执行完时,启动第二次,他会直接从onStartCommand开始执行。而不是像第一次一样按循序执行。

IntentService的建立循序:

1)新建的类会继承IntentSrevice。

2)重写onHandleIntent()方法。许多操作基本上都是在这个方法中写的。

3)在Activity中像执行Service一样去启动IntentService。

4)记住,一定要注册:

<service android:name=".myIntentSrevice"/>


代码如下:


public class myIntentSrevice extends IntentService {
int count;
/**
* Creates an IntentService.  Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public myIntentSrevice(String name) {
super(name);
}
//必须写这个才能注册
public myIntentSrevice() {
this("");
}
@Override
protected void onHandleIntent(Intent intent) {
while (count<100){
if(count==99){
count=0;
}
count++;
Intent intent2 =new Intent("com.pp");
//                    intent.setAction("com.pp");
intent2.putExtra("count",count);
sendBroadcast(intent2);//在线程中启动广播
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

@Override
public void onDestroy() {
Log.d("","结束service");
super.onDestroy();
}
}


在Activity中:

Intent intent3= new  Intent(getApplicationContext(),myIntentSrevice.class);
startService(intent3);


Looper,Message,Handler三者之间的关系

线程与进程

在android中一个应用就是一个进程,在一个进程中可以有多个线程。

其中最重要的一个线程是UI主线程,他就像我们看电影一样在界面中不停的画view。UI主线程是不允许其他线程修改UI的View的。当必须由子线程修改view时,就可以用Looper,Message,Handler三者之间的关系之间的关系来解决。也可以用AsyncTask,这个等会再说。

其图如下;



在主线程中建立一个Handler并复写方法handleMessage()(大多数操作都在这里)接受消息,在子线程中用主线程建立的Handler对象发送message消息。

记住在主线程建立Handler对象后就形成了一个MessageQueue——Looper机制。当子线程发送消息给主线程,这个消息会放在MessageQueue中。当主线程运行到MessageQueue时会将数据取走。

下面我们写一个倒计时的例子:

private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case DESC:
button_desc.setText((String) msg.obj);
break;
}
}
} ;

case R.id.button_desc:
new Thread(new Runnable() {
@Override
public void run() {
while (count>0){
count--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Message message =new Message();
Message message=  handler.obtainMessage(); //它会获得一个用过的message对象,没有的话会自动建立。
message.obj=count+"秒";//赋予要传递的数据
message.what=DESC;//这类消息的标示。
handler.sendMessage(message);
}
}
}).start();
break;


在按键的点击事件中:

// Message message =new Message();
Message message=  handler.obtainMessage(); //它会获得一个用过的message对象,没有的话会自动建立。
message.obj=count+"秒";//赋予要传递的数据
message.what=DESC;//这类消息的标示。
handler.sendMessage(message);//发送这个消息


第二种写法:

private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case DESC:
count--;
button_desc.setText(count+"秒");
if(count>0){
try {
Thread.sleep(1000);
handler.sendEmptyMessage(DESC);
} catch (InterruptedException e) {
e.printStackTrace();
}

}

break;
}
}
} ;

case R.id.button_desc:

handler.sendEmptyMessage(DESC);//再次发送一个空消息


Handler补偿说明:

(1)Handler.post()的用法:可以在子线程中调用handler.post()在post包含的Runnable()的run方法中更新UI。

代码:

new Thread(){
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
firstEdit.setText("hahahhaha");
}
});

}
}.start();


(2) handler.postDelayed(myRunnable,1000);可以进行定时更新UI操作。

1)建立一个继承自Runnale的类,在run方法中更新Ui。

2)建立这个类的对象,在oncreat()和继承自Runnale的类的runn()中调用 handler.postDelayed(myRunnable,1000);这样就可以

定时实现更新UI的操作了。

代码如下:
private MyRunnable myRunnable = new MyRunnable();
class MyRunnable implements Runnable{

@Override
public void run() {
index++;
index = index%3;
imageView.setImageResource(images[index]);
handler.postDelayed(myRunnable,1000);

}
}


在oncreat()中:

handler.postDelayed(myRunnable,1000);

(3) handler.removeCallbacks(myRunnable);

用于移除Runnable的回调机制。当调用这行代码的时候 handler.postDelayed(myRunnable,1000);中的myRunnable就不起作用了。

(4)Message:Handler可以通过发送message来传递给主线程一些小消息。要发送消息,必须有消息。可以通过两种方式获得Message

:Message message = new Message();或者 Message message = handler.obtainMessage();//这个是获得系统的闲置的Message。

如果没有闲置的会自动给你生成一个。

消息载体是: message.arg1 =88;//message.arg1 是int类型的载体。如果想传递字符串或其他的对象可以用message.obj=?//可以是

字符串,各种对象。发送有两种形式: handler.sendMessage(message);//这一种是比较常用的。如果用Message message =

handler.obtainMessage();生成message的话,可以用message.sendToTarget();发送,否则不可以。

发送的消息会在handler的handleMessage()函数中接收的,一般先判读是否是这个消息。用handler.what或者

handler.arg1/2判断。

代码如下:
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Toast.makeText(getApplicationContext(),""+msg.what,Toast.LENGTH_SHORT).show();
}
};

public void onClick(View view) {

new Thread(new Runnable() {
@Override
public void run() {
Message message = handler.obtainMessage();//如果这样获得message,可以这样发送:

message.sendToTarget();
//  否则不可以这样发送用这个发送:handler.sendMessage(message);。
message.arg1 =88;
message.sendToTarget();
handler.sendMessage(message);
handler.sendEmptyMessage(1);//还可以发空字符串。
}
}).start();

}
});
}


(5)在创建handler的时候还可以在构造器中添加Callback()的对象,在这个类中也有一个handleMessage方法,只不过它有返回值。这

是一个拦截机制,在发送过来的消息会先在Callback中处理,如果返回false在这里处理完后会再在handler的handleMessage方法中处

理。如果返回true。则此消息不会再往下传。

Handler Looper MessageQueue三者之间的关系:

一,Handler封装了消息的发送(主要包括消息发送给谁)

Looper

1.内部包含一个消息队列也就是MessageQueue,所有发送的handler发送的消息都走这个消息队列。

2.Looper.Looper方法就是一个死循环,不断的从MessageQueue中取消息,如果有消息就处理消息,如果没有就阻塞。

二.MessageQueue,就是一个消息队列,可以添加消息和处理消息

三.handler内部会跟Looper进行关联,也就是说在handler的内部就可以找到Looper,找到了Looper也就找到了MessageQueue,在

Hnadler中发送消息也就是向MessageQueue中发送消息。

总结:Handler负责发送消息,Looper负责接收Handler发送的消息,并把消息回传给Handler自己。MessageQueue就是存储消息的容器



HandlerUI主线程给子线程发送消息。

在子线程中建立Handler的对象,在UI主线程中调用这个对象的引用,并发送消息。注意。在子线程中必须自己建立Looper对象: Looper.prepare();//创建Looper对象.并且调用Looper.loop()方法。在这之间初始化Handler的对象,重写handleMessage()方法

代码如下:
class MyThread extends Thread{
Handler handler;
@Override
public void run() {
Looper.prepare();//创建Looper对象
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Toast.makeText(getApplicationContext(), ""+msg.what, Toast.LENGTH_SHORT).show();
}
};
//            Toast.makeText(getApplicationContext(), "aaaaa", Toast.LENGTH_SHORT).show();
Looper.loop();//实现消息的循环处理
}
}


注意:

在UI主线程中thread.start();时不可以立刻发送消息: thread.handler.sendEmptyMessage(1);这样会有空指针的错误,应该延迟一段时间。

Handler绑定Looper

在创建Handler对象的时候可以不用默认的Looper对象是可以绑定你指定的某个线程的Looper对象。例如:

handler = new Handler(thread.getLooper())这就是绑定了threadThread的Looper对象,当handler与某个线程的Looper对象绑定时

handleMessage()方法就会在这个线程中执行而不是Handler所在的对象执行。

但是如果随便的绑定一个线程的Looper对象的话,可能会由于线程的不同步等问题会有空指针的问题出现(在绑定这个线程的Looper的时候可能还没有创建成功),为了避免这种问题的发生,google开发了一种HandlerThread的线程,这个线程就有Looper对象在我们调用thread.getLooper()的时候会先判断Looper是否为空,如果为空就等待,当Looper创建成功的时候会通知它,然后再执行。这样就避免了多线程不同步引起的空指针的问题。这样我们也可以在handleMessage()中执行一些耗时操作了。

用Hnadler机制实现主线程与子线程之间的通信。

建立两个Handler实例,都是在UI中建立的,只不过有一个Handler的实例是绑定的子线程的Looper。这样就可以用这个Handler的实例在子线程中实现接收主线程的消息了。完整如下:

public class MainActivity extends AppCompatActivity {
private TextView firstEdit;
private Button myFirstbutton;
private ImageView imageView;

private Handler threadHandler;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
threadHandler.sendEmptyMessageDelayed(2,1000);
Log.d("aaaa",""+Thread.currentThread());
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  WindowManager.LayoutParams.FLAG_FULLSCREEN);

setContentView(R.layout.activity_main);
firstEdit = (TextView) findViewById(R.id.first_edit);
myFirstbutton = (Button) findViewById(R.id.first_button);
imageView = (ImageView) findViewById(R.id.myImageView);
HandlerThread thread = new HandlerThread("Handler Thread");
thread.start();
threadHandler = new Handler(thread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
handler.sendEmptyMessageDelayed(1,1000);
Log.d("aaaa",""+Thread.currentThread());
}
};

myFirstbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
handler.sendEmptyMessage(1);

}
});

}

}


四种更新UI的方法

方法一:handler.post(new Runnable(){

run(){

}

})

方法二:

handler.setmaeesge()在handler的handleMessage()方法中更新UI;

方法三

调用view的post方法。

firstEdit.post(new Runnable() {
@Override
public void run() {
firstEdit.setText("hehelooooooo");
}
});


方法四

调用runOnUiThread()方法:

runOnUiThread(new Runnable() {
@Override
public void run() {
firstEdit.setText("heheloooooooooo");
}
});


主线程向子线程发送消息

在主线程给子线程发送消息时,子线程的run()方法的代码的handler的代码必须放在 Looper.prepare();和 Looper.loop();这两行代码之间。但在主线程中建立Handler时,主线程是默认就有的,所以不需要写。

MyThread thread = new MyThread();

thread.start();

与 handler.sendEmptyMessage(0);这两行代码不可以在一起,因为启动线程需要时间而handler.sendEmptyMessage(0)的执行时间很小。所以在线程还没有启动的时候,主线程就已经发送消息了,会造成空指针。

代码如下:
private Handler handler;
class MyThread extends Thread{
@Override
public void run() {
Looper.prepare();
handler =new Handler(){
@Override
public void handleMessage(Message msg) {
Log.d("thread","我收到了");
}
};

Looper.loop();
}
}

//在点击事件中
case R.id.button_desc:
MyThread thread = new MyThread();
thread.start();

case R.id.button_send:
//                Message message =handler.obtainMessage();
//               handler.sendMessage(message);
handler.sendEmptyMessage(0);
break;


AsyncTask

AsyncTask的基本原理与Handler是一样的,就是用Handler进行封装的,只不过

可以在其中的方法中可以对View进行操作,一般是以内部类的形式存在的。

操作顺序如下:

1)写一个类继承于AsyncTask(String,Integer,String)(是尖括号哦)

第一个参数为doInBackground的参数,最后一个是doInBackground的返回值的leixing

第二个参数为onProgressUpdate接受的第一个参数。

doInBackground()为后台运行过程。onPostExecute(String s)为运行结束时的操作。

onProgressUpdate()为在运行过程中对view的操作。

onPostExecute()和onProgressUpdate()可以对view进行操作。

doInBackground()的publishProgress(count);为调用onProgressUpdate()方法。

2)在Activity的某个位置建立此类的对象。并调用execute(“”)方法。

写一个下载的例子:

class MyAsyncTask extends AsyncTask<String,Integer,String>{
@Override
protected String doInBackground(String... params) {
while (count<101){
count++;
publishProgress(count);//调用onProgressUpdate()方法
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

return "全部传完了哦";
}

@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
down_button.setText(s);
}

@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressBar.setProgress(values[0]);//在参数不确定的时候values是以数组的形式处理

的
}
}
}

case R.id.down_button:
MyAsyncTask myAsyncTask =new MyAsyncTask();
myAsyncTask.execute("dd");//dd是随便写的。
break;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: