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

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值