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

来源:互联网 发布:js走马灯效果 编辑:程序博客网 时间:2024/06/15 10:41

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;
0 0
原创粉丝点击