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;
相关文章推荐
- tomcat 之startup.bat文件
- operator new 函数、operator delete 函数 和 定位 new
- linux下jsoncpp的编译和测试使用
- [分布式系统]-分布式消息系统:Kafka
- 系统调用原理
- AOP入门一
- POJ 2112 Optimal Milking【二分+最大流】
- wr703n路由器搭载openwrt系统挂载U盘历程
- linux 初级阶段整理笔记
- 网站添加favicon.ico图标
- centos 下面安装lamp
- mac install tomcat8
- Linux(Ubuntu-GNOME)桌面常用快捷方式总结
- 浅谈Linux文件系统
- linux磁盘分区fdisk命令详解
- Hadoop学习笔记六之 URLClassLoader && ConnectionRefused 异常
- tomcat server.xml配置介绍
- qrencode二维码生成在linux下的编译(转)
- Linux 文件查看常用命令
- linux文件查找命令