精华内容
下载资源
问答
  • 安卓 线程

    2018-10-11 23:21:55
    安卓 线程 一、简述  记--安卓编程中线程的简单使用例子。使用匿名方式、继承方式创建线程。  代码文件:链接: https://pan.baidu.com/s/10saeJ5XxDOpWokn9vB6Y1w 提取码: pkfu 二、方式1--匿名类   // ...

    安卓 线程

    一、简述

          记--安卓编程中线程的简单使用例子。使用匿名方式、继承方式创建线程。

          代码文件:链接: https://pan.baidu.com/s/10saeJ5XxDOpWokn9vB6Y1w 提取码: pkfu

    二、方式1--匿名类

            

            // 开启子线程
            new Thread(){
               @Override
         	   public void run(){
    
         		    //子线程执行的动作,比如执行test()函数
                    test();
         	   }  
            }.start(); 

    例子: 有一个int类型的成员num,子线程每隔一秒将num加2,点击主线程中的按钮将num的当前值显示到TextView。

            代码结构

                 

     

            布局:

             2.2 效果

                                           

                 注:TextView控件没有立即更新,需要手动更新,所以看到本来是每隔1秒追加打印num的值变为"一股脑"更新了。

            源码文件

                     MainActivity.java文件

    package com.example.testthread;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;
    import android.widget.Toast;
    import android.app.Activity;
    
    public class MainActivity extends Activity {
    
    	private int num = 1;
    	
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
         // 开启子线程
            new Thread()
            {
            	@Override
            	public void run()
            	{
            		//子线程要执行的动作,每隔1秒就将num+2
            		while(true)
            		{
            			num += 2;
            			Sleep(1000);//延时1秒
            		}
            	}
            	
            }.start();
            Toast.makeText(this, "子线程1创建完毕!", Toast.LENGTH_SHORT).show();
        }
    
        public void on_btn_main_thread_Clicked(View v)
        {
        	Toast.makeText(this, "主线程!", Toast.LENGTH_SHORT).show();
        	TextView tv = (TextView)findViewById(R.id.tv_main_thread);
        	for(int i=0; i<20; i++)
        	{
        		tv.append("num="+num+"\n");
        		Sleep(500);
        	}
        }
        
       public void Sleep(long ms)
       {
    	   try {
    			Thread.sleep(ms);//延时ms毫秒
    	   } catch (InterruptedException e) {
    	// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
       }
    }
    

    三、方式2--自定义类继承Thread类

           方式1的匿名类方式虽然操作"简单",但是难以"控制",比如没有一个实际的操作对象,就不方便在后面进行对子线程的控制,如对子线程的休眠、停止、销毁等操作。还有就是匿名方式不方便"重用"。

          自定义一个类继承Thread类,并重写run方法

    public class MyThread extends Thread {  
        @Override
        public void run(){  
            //要执行的动作
        }  
    } 

    创建子线程并启动 

    new MyThread().start();//开启子线程,执行run()方法
    
    或
    
    MyThread thread1 = new MyThread();
    thread1.start();

    例子: 有一个int类型的成员num,子线程每隔一秒将num加2,点击主线程中的按钮将num的当前值显示到TextView。

    代码结构

    效果:

                                        

    源码文件

                     MainActivity.java文件

     

    package com.example.testthread;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;
    import android.widget.Toast;
    import android.app.Activity;
    
    public class MainActivity extends Activity {
    
    	private int num = 1;
    	
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
         // 开启子线程
         new Mythread().start();   
         Toast.makeText(this, "子线程1创建完毕!", Toast.LENGTH_SHORT).show();
        }
    
        public void on_btn_main_thread_Clicked(View v)
        {
        	Toast.makeText(this, "主线程!", Toast.LENGTH_SHORT).show();
        	TextView tv = (TextView)findViewById(R.id.tv_main_thread);
        	for(int i=0; i<20; i++)
        	{
        		tv.append("num="+num+"\n");
        		Sleep(500);
        	}
        }
        
        public class Mythread extends Thread
        {
            	@Override
            	public void run()
            	{
            		//子线程要执行的动作,每隔1秒就将num+2
            		while(true)
            		{
            			num += 2;
            			Sleep(1000);//延时1秒
            		}
            	}
        }
        
       public void Sleep(long ms)
       {
    	   try {
    			Thread.sleep(ms);//延时ms毫秒
    	   } catch (InterruptedException e) {
    	// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
       }
    }
    

    四、问题总结

    1、子线程更新UI(控件)问题。

            测试代码1:在子线程中成功改变TextView控件的文本。

    package com.example.testthread;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;
    import android.widget.Toast;
    import android.app.Activity;
    
    public class MainActivity extends Activity {
    
    	private int num = 1;
    	
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
           // 开启子线程
            new Thread()
            {
            	@Override
            	public void run()
            	{
            		//子线程要执行的动作
        			TextView tv = (TextView)findViewById(R.id.tv_main_thread);
        			tv.setText("子线程正在运行。。。");
            	}
            	
            }.start();
            Toast.makeText(this, "子线程1创建完毕!", Toast.LENGTH_SHORT).show();
        }
    
        public void on_btn_main_thread_Clicked(View v)
        {
        	Toast.makeText(this, "主线程!num="+num, Toast.LENGTH_SHORT).show();
        }
        
        public void Sleep(long ms)
        {
     	   try {
     			Thread.sleep(ms);//延时ms毫秒
     	   } catch (InterruptedException e) {
     	// TODO Auto-generated catch block
     			e.printStackTrace();
     		}
        }
    }
    

    运行结果:

                                

     测试代码2:在测试代码1的基础上修改"子线程执行的动作"部分,成功运行。

                    //子线程要执行的动作
        			TextView tv = (TextView)findViewById(R.id.tv_main_thread);
        			tv.setText("子线程正在运行");
        			num += 2;
        			Sleep(1000);

    运行结果:

                                     

    测试代码3:在测试代码2的基础上修改"子线程执行的动作"部分,延时1秒,二次更改TextView控件的文本,程序崩溃。

                    //子线程要执行的动作
        			TextView tv = (TextView)findViewById(R.id.tv_main_thread);
        			tv.setText("子线程正在运行");
        			num += 2;
        			Sleep(1000);
        			tv.setText("num="+num);

    运行结果:

                                                      

    2、如何手动立即更新UI?

          在方式1--匿名类中的按钮单击响应代码效果,并没有立即改变TextView控件

        public void on_btn_main_thread_Clicked(View v)
        {
        	Toast.makeText(this, "主线程!", Toast.LENGTH_SHORT).show();
        	TextView tv = (TextView)findViewById(R.id.tv_main_thread);
        	for(int i=0; i<20; i++)
        	{
        		tv.append("num="+num+"\n");
        		Sleep(500);
        	}
        }

    使用Handler更新UI,只需在需要的时候发送一个信号。(有点像Handler是一个独立线程,收到一个信号就进行动作)

    例子:子线程每隔1秒发送一个信号给handler,通知handler改变TextView的文本。主线程能够随时的打印num的值。

    测试代码:

    package com.example.testthread;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.view.View;
    import android.widget.TextView;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    
    	private int num;
    	private TextView tv;
        private Handler handler = new Handler(){
    		@Override
            public void handleMessage(Message msg){
    			switch(msg.what){
    				case 0:
    						tv.setText(num+"");//改变TextView控件的文本
    				default:
    					break;
    			}
            }
    	};
    	
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            num = 1;
            tv = (TextView)findViewById(R.id.tv_main_thread);//拿到TextView对象
            
            //开启子线程
            new Thread()
            {
            	@Override
            	public void run()
            	{
            		while(true)//每隔1秒发送一个0信号给handler
            		{
            			handler.sendEmptyMessage(0);//发送一个0信号给handler,通知handler更新UI
            			num++;
            			Sleep(1000);//延时1秒
            		}
            	}
           	
            }.start();
            
            Toast.makeText(this, "子线程1创建完毕!", Toast.LENGTH_SHORT).show();
        }
    
        public void on_btn_main_thread_Clicked(View v)
        {
        	Toast.makeText(this, "主线程!num="+num, Toast.LENGTH_SHORT).show();
        	
        }
        
        public void Sleep(long ms)
        {
     	   try {
     			Thread.sleep(ms);//延时ms毫秒
     	   } catch (InterruptedException e) {
     			e.printStackTrace();
     		}
        }
    
    }
    

    运行结果:

                             

    其中发送信号给Handler:
          handler.sendEmptyMessageDelayed(0, 1000);//1秒后发送0信号。
          handler.sendEmptyMessage(0);//发送0信号

     

    展开全文
  • 安卓线程

    2019-06-29 09:00:09
    关于线程和进程 1.进程是资源管理的最小单位 线程是程序执行的最小单位 2.每个进程都有自己的数据段 代码段 和堆栈段 线程 通常叫做 轻型的进程 它包含独立的栈和CPU寄存状态 每个线程共享其所附属进程的所有...

    关于线程和进程

     

    1.进程是资源管理的最小单位 线程是程序执行的最小单位

     

    2.每个进程都有自己的数据段 代码段 和堆栈段 线程 通常叫做 轻型的进程 它包含独立的栈和CPU寄存状态 每个线程共享其所附属进程的所有资源 包含打开的文件 内存页面 信号标识及分配内存等。

     

    3.线程比进程花费更小的CPU资源

     

    4.在操作系统设计上 从进程演化出线程 最主要的目的就是更好的支持多处理器 并且减少进程上下文切换的开销 线程的上下文切换比进程快很多

     

    5.进程和线程的关系 线程属于进程 线程运行在进程空间内 统一进程所产生的线程共享同一内存控件 当进程退出所产生的线程会被强制退出并且清楚 一个进程至少需要一个线程来作为他的指令执行体 进程管理着资源 比如CPU 内存 文件 等等,而将线程分配到某个CPU上运行

     

    6.线程按照其调度这可以分为用户级线程和内核级线程两种

    用户级线程:主要解决的是上下文切花你的问题 其调度过程由用户决定(开发者决定)

    内核级线程:通过内核调度实现

     

    7.用户级线程要绑定内核级线程使用

     

    8.默认情况下不能保证新线程和调用线程执00行顺讯

     

    9.每个进程内部的不同线程都有自己的唯一标识(ID) 线程标识只在它所属的进程环境中有效

     

    10.Sleep线程告诉系统 自己在一段时间内不被调度

     

    线程中各种唤醒 等待 睡眠方法之间的区别:

    1.notify()和notifyAll()方法的区别:

    notifyAll是所有在当前对象上等待被notify的线程都退出wait状态 变成等待该对象上的锁 一旦该对象被解锁 他们就会去竞争 。 但是notify仅仅只是选择一个在wait状态的线程进行通知 并或者该对象上的锁 而且并不会惊动同样在等待被该对象notify的线程,当第一个线程运行完毕后释放对象上的锁 此时如果该对象没有再次使用notify语句 则即便该对象已经空闲 其他wat状态等待的线程由于没有得到该对象的通知 继续处在wait状态 直到这个对象发出一个 notify或notifyAll ,线程在wait状态时等待的是被notify和notifyAll 而不是锁

     

    2.sleep() yield() 和 wait() 方法之间的区别

    ①:sleep()使当前线程暂停一段时间 让其他线程有机会继续执行,但是并不释放对象锁。也就是如果有Synchronized同步块 其他线程仍然不能访问共享数据 注意该方法要捕获异常 ,如果两个线程同时执行 没有Synchronized的情况下 一个线程优先级为MAX 另一个为MIN 如果没有Sleep()方法,那么只有当优先级高的执行完 优先级低的才能执行 但是档优先级高的线程Sleep(5000)之后 低优先级的线程就有机会执行了。

     

    ②:wait()方法使当前线程暂停执行并释放对象锁标志 让其他线程可以进入Synchronized数据块 当前线程被放入对象等待池中 只有 锁标志等待池中的线程能够获取锁标志 如果锁标志等待池中没有线程 则notify()不齐作用

     

    ③:yield、可以使当前线程放弃当前分的CPU时间 但是并不会使线程阻塞 即线程仍处理可执行状态 随意可能再次分的CPU时间 调用yieid()的效果等价于调度程序认为该线程已经执行足够的时间而转到另一个线程 yieid()只是使当前线程重新回到可执行状态 所以执行yieid() 的线程有可能在进入可执行状态后又马上被执行 sleep()可以使优先级低的线程获取先执行的机会 但是同样也可以让同级优先和高优先级的线程有执行的机会 yieid()只能使同优先级的线程有执行的机会

     

    3.suspend() 和 resume() 方法之间的区别

    suspend() 和 resume() 两个方法配套使用 suspend()使得线程进入阻塞状态 必须其对象的resume()被调用 才能使得线程重新进入可执行状态 但是当这两个方法被用在等待另一个线程产生的结果情形 当另一个线程出现结果调用resume让其恢复

     

     

     

     

     

     

    展开全文
  • 安卓线程的简单使用例子
  • Android--从Java线程到安卓线程

    千次阅读 2016-04-25 21:34:49
    写在前面:本文为安卓线程与JAVA线程的异同,请多多指正! 简述:相信很多学安卓的都是从java入门之后开始进行安卓的学习,而当我们面临安卓线程的书写的时候,发现安卓线程并不是我们想象中使用java的线程写法就...

    写在前面:

    本文为安卓线程与JAVA线程的异同,请多多指正!
    

    简述:

    相信很多学安卓的都是从java入门之后开始进行安卓的学习,而当我们面临安卓线程的书写的时候,发现安卓线程并不是我们想象中使用java的线程写法就可以。
    
    • java线程的语法移植出错了?

    这里我们简单的书写一个TextClock(由TextView 和Calendar组成),这里的Button用于终止时间。这里我们使用java上线程的写法来:

    public class MainActivity extends AppCompatActivity {
    
        private TextView textView;
        private boolean flag = true;//用于控制线程
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while(flag){
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTimeInMillis(System.currentTimeMillis());
                        int hour = calendar.get(Calendar.HOUR_OF_DAY);
                        int minute = calendar.get(Calendar.MINUTE);
                        int sec = calendar.get(Calendar.SECOND);
                        String string = new String(hour + " : " + minute + " : " + sec);
                        textView = (TextView)findViewById(R.id.test);
                        textView.setText(msg.obj.toString());
                        try{
                            Thread.currentThread().sleep(100);
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
            Button button = (Button)findViewById(R.id.Btn);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    flag = false;
                    Toast.makeText(MainActivity.this,"You click here!",Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

      现在分析一下上面的案例,在上面的程序中有两个线程:一个主线程和一个子线程,它们的职责如图所示。
    这里写图片描述
    上述实例中的处理利用子线程进行了UI界面的更新,违背了Android多线程编程规则,系统会抛出异常“Only the original thread that created a view hierarchy can touch its views”。

    要解决这个问题,就要明确主线程和子线程的职责。主线程的职责是创建、显示和更新UI控件、处理UI事件、启动子线程、停止子线程;子线程的职责是计算逝去的时间和向主线程发出更新UI消息,而不是直接更新UI。

    主线程的职责是显示UI控件、处理UI事件、启动子线程、停止子线程和更新UI,子线程的职责是计算逝去的时间和向主线程发出更新UI消息。但是新的问题又出现了:子线程和主线程如何发送消息、如何通信呢?

    • 利用Handler和message处理子进程
      由于布局很简单,我们这里不进行布局代码的阐述,以下为主活动代码:
    public class MainActivity extends AppCompatActivity {
    
        private TextView textView;
        private boolean flag = true;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            /*使用Handler进行更新页面*/
            final android.os.Handler handler = new android.os.Handler(){
                @Override
                public void handleMessage(Message msg) {
                    switch(msg.what){/*接收来自子线程之间的message*/
                        case 0:{/*根据来源执行不同的操作*/
                            textView = (TextView)findViewById(R.id.test);
                            textView.setText(msg.obj.toString());/*文本更新*/
                        }
                    }
                    super.handleMessage(msg);
                    //这里最好对不需要或者不关心的消息抛给父类,避免丢失消息  
                }
            };
            new Thread(new Runnable() {//利用Runnable接口实现线程
                @Override
                public void run() {
                    while(flag){
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTimeInMillis(System.currentTimeMillis());
                        int hour = calendar.get(Calendar.HOUR_OF_DAY);
                        int minute = calendar.get(Calendar.MINUTE);
                        int sec = calendar.get(Calendar.SECOND);
                        String string = new String(hour + " : " + minute + " : " + sec);
                        //上述为计算操作
                        Message message = new Message();//初始化消息对象
                        message.obj = string;//将想要发送的消息添加到消息中
                        message.what = 0;//设置message来源为0
                        handler.sendMessage(message);//给handler发送消息
                        try{//线程休眠
                            Thread.currentThread().sleep(100);
                            //Thread代表线程,currentThread()代表获取当前线程,sleep()代表睡眠
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
            Button button = (Button)findViewById(R.id.Btn);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    flag = false;
                    Toast.makeText(MainActivity.this,"You click here!",Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    更加具体的消息机制请访问
    Android的Message机制(简单小结) - ·没有风雨躲得过,没有坎坷不必走· - 博客频道 - CSDN.NET
    http://blog.csdn.net/dadoneo/article/details/7667726

    这样子我们就简单的做了一个计时器app,利用线程成功实现了计时并更新数据。

    • 利用TimeTask和Handler实现
      在Android平台中需要反复按周期执行方法可以使用Java上自带的TimerTask类,TimerTask相对于Thread来说对于资源消耗的更低,除了使用Android自带的AlarmManager使用Timer定时器是一种更好的解决方法。 我们需要引入import java.util.Timer; 和 import java.util.TimerTask;
    public class MainActivity extends AppCompatActivity {
    
        private TextView textView;
        private android.os.Handler handler;
        private boolean flag = true;
        Timer timer = new Timer();//实例化Timer
        TimerTask timerTask = new TimerTask() {//实例化TimerTask
            @Override
            public void run() {
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(System.currentTimeMillis());
                int hour = calendar.get(Calendar.HOUR_OF_DAY);
                int minute = calendar.get(Calendar.MINUTE);
                int sec = calendar.get(Calendar.SECOND);
                String string = new String(hour + " : " + minute + " : " + sec);
                Message message = new Message();//实例消息
                message.obj = string;
                message.what = 0;
                handler.sendMessage(message);
            }
        };
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            handler = new android.os.Handler(){
                @Override
                public void handleMessage(Message msg) {
                    switch(msg.what){
                        case 0:{
                            textView = (TextView)findViewById(R.id.test);
                            textView.setText(msg.obj.toString());
                        }
                    }
                    super.handleMessage(msg);
                }
            };
            timer.schedule(timerTask,1000,100);//注释一
    
            Button button = (Button)findViewById(R.id.Btn);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    flag = false;
                    Toast.makeText(MainActivity.this,"You click here!",Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    [ 注释一 ]:timer.schedule(new MyTask(),long time1,long timer2);
    第一个参数,是 TimerTask 类,在包:import java.util.TimerTask .使用者要继承该类,并实现 public void run() 方法,因为 TimerTask 类 实现了 Runnable 接口。
    第二个参数的意思是,当你调用该方法后,该方法必然会调用 TimerTask 类 TimerTask 类 中的 run() 方法,这个参数就是这两者之间的差值,转换成汉语的意思就是说,用户调用 schedule() 方法后,要等待这么长的时间才可以第一次执行 run() 方法。
    第三个参数的意思就是,第一次调用之后,从第二次开始每隔多长的时间调用一次 run() 方法。
    [附:]
      技术人员在实现内部办公系统与外部网站一体化的时候,最重要的步骤就是从OA系统读取数据,并且根据网站模板生成最终的静态页面。这里就需要一个定时任务,循环的执行。
      技术人员在写定时任务的时候,想当然的以为Timer.schedule(TimerTask task, long delay)就是重复的执行task。程序运行后发现只运行了一次,总觉得是task里的代码有问题,花了很长时间调试代码都没有结果。
      仔细研读java api,发现:
      schedule(TimerTask task, long delay)的注释:Schedules the specified task for execution after the specified delay。大意是在延时delay毫秒后执行task。并没有提到重复执行
      schedule(TimerTask task, long delay, long period)的注释:Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay。大意是在延时delay毫秒后重复的执行task,周期是period毫秒。
      这样问题就很明确schedule(TimerTask task, long delay)只执行一次,schedule(TimerTask task, long delay, long period)才是重复的执行。关键的问题在于程序员误以为schedule就是重复的执行,而没有仔细的研究API,一方面也是英文能力不够,浏览API的过程中不能很快的理解到含义。

    • 知识点补充

    很多初入Android或Java开发的新手对Thread、Looper、Handler和Message仍然比较迷惑,衍生的有HandlerThread、java.util.concurrent、Task、AsyncTask由于目前市面上的书籍等资料都没有谈到这些问题,今天就这一问题做更系统性的总结。我们创建的Service、Activity以及Broadcast均是一个主线程处理,这里我们可以理解为UI线程。但是在操作一些耗时操作时,比如I/O读写的大文件读写,数据库操作以及网络下载需要很长时间,为了不阻塞用户界面,出现ANR的响应提示窗口,这个时候我们可以考虑使用Thread线程来解决。

    对于从事过J2ME开发的程序员来说Thread比较简单,直接匿名创建重写run方法,调用start方法执行即可。或者从Runnable接口继承,但对于Android平台来说UI控件都没有设计成为线程安全类型,所以需要引入一些同步的机制来使其刷新,这点Google在设计Android时倒是参考了下Win32的消息处理机制。

    1. 对于线程中的刷新一个View为基类的界面,可以使用postInvalidate()方法在线程中来处理,其中还提供了一些重写方法比如postInvalidate(int
      left,int top,int right,int bottom)
      来刷新一个矩形区域,以及延时执行,比如postInvalidateDelayed(long
      delayMilliseconds)或postInvalidateDelayed(long delayMilliseconds,int
      left,int top,int right,int bottom) 方法,其中第一个参数为毫秒

    2. 当然推荐的方法是通过一个Handler来处理这些,可以在一个线程的run方法中调用handler对象的 postMessage或sendMessage方法来实现,Android程序内部维护着一个消息队列,会轮训处理这些,如果你是Win32程序员可以很好理解这些消息处理,不过相对于Android来说没有提供
      PreTranslateMessage这些干涉内部的方法。

    3. Looper又是什么呢? ,其实Android中每一个Thread都跟着一个Looper,Looper可以帮助Thread维护一个消息队列,但是Looper和Handler没有什么关系,我们从开源的代码可以看到Android还提供了一个Thread继承类HanderThread可以帮助我们处理,在HandlerThread对象中可以通过getLooper方法获取一个Looper对象控制句柄,我们可以将其这个Looper对象映射到一个Handler中去来实现一个线程同步机制,Looper对象的执行需要初始化Looper.prepare方法就是昨天我们看到的问题,同时推出时还要释放资源,使用Looper.release方法。

    4. Message 在Android是什么呢?
      对于Android中Handler可以传递一些内容,通过Bundle对象可以封装String、Integer以及Blob二进制对象,我们通过在线程中使用Handler对象的sendEmptyMessage或sendMessage方法来传递一个Bundle对象到Handler处理器。对于Handler类提供了重写方法handleMessage(Message
      msg)
      来判断,通过msg.what来区分每条信息。将Bundle解包来实现Handler类更新UI线程中的内容实现控件的刷新操作。相关的Handler对象有关消息发送sendXXXX相关方法如下,同时还有postXXXX相关方法,这些和Win32中的道理基本一致,一个为发送后直接返回,一个为处理后才返回
      .

    5. java.util.concurrent对象分析,对于过去从事Java开发的程序员不会对Concurrent对象感到陌生吧,他是JDK 1.5以后新增的重要特性作为掌上设备,我们不提倡使用该类,考虑到Android为我们已经设计好的Task机制,这里不做过多的赘述,相关原因参考下面的介绍:

    6. 在Android中还提供了一种有别于线程的处理方式,就是Task以及AsyncTask,从开源代码中可以看到是针对Concurrent的封装,开发人员可以方便的处理这些异步任务。

    摘录自:http://www.cnblogs.com/playing/archive/2011/03/24/1993583.html

    展开全文
  • 安卓线程异步处理的小结 概念了解 Android会存在两种线程:一种是UI主线(UI Thread)程一种是工作线程(Work Thread) 在子线程中处理耗时的任务,任务完成后通过Handler通知UI主线程更新UI界面 主线程不允许进行耗时的...

    安卓线程异步处理的小结

    概念了解

    Android会存在两种线程:一种是UI主线(UI Thread)程一种是工作线程(Work Thread)
    在子线程中处理耗时的任务,任务完成后通过Handler通知UI主线程更新UI界面
    主线程不允许进行耗时的操作(比如说网络请求和访问),否则容易出现ANR现象
    ANR
    anr:application not reponse:应用程序无响应
    主线程:UI线程
    anr产生的原因:主线程需要做很多重要的事情,响应点击事件,更新ui,如果在主线程里面阻塞时间过久,应用程序就会无响应,为了避免应用程序出现anr,所有的耗时的操作,都应该放在子线程中执行。

    Android 异步消息处理机制解析

    Android异步消息处理主要分为四个部分,MessageHandlerMessageQueueLooper

    Message

    Message 是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。通常使用 Message 的 what 字段携带命令,除此之外还可以使用 arg1 和arg2 字段来携带一些整形数据,使用 obj 字段携带一个 Object 对象
    使用示例

    var message=Message()
    message.what=0x123
    message.obj=1
    handlerMess.sendMessage(message)
    
     //在主线程中创建一个Handler
        var handlerMess: Handler = object : Handler() {
            //处理消息
            override fun handleMessage(msg: Message) {
                super.handleMessage(msg)
                when (msg.what) {
                    0x123 -> {
                        Log.i("Message","Message="+msg.obj)
                    }
                }
            }
        }
    

    返回结果:
    Message=1

    Handler

    Handler 顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用 Handler 的 sendMessage()方法,而发出的消息经过一系列地辗转处理后,最终会传递到 Handler 的 handlerMessage()方法中。

    MessageQueue

    MessageQueue 是消息队列的意思,它主要用于存放所有通过 Handler 发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个 MessageQueue 对象。

    Looper

    Looper 是每个线程中的 MessageQueue 的管家,调用 Looper 的 loop() 方法后,就会进入到一个无限循环当中,然后每当发现 MessageQueue 中存在一条消息,就会将它取出,并传递到 Handler 的 handleMessage() 方法中。每个线程中也只会有一个 Looper 对象。

    Android提供了四种常用的操作多线程的方式

    1. Thread

    使用示例

      Thread{
          tv_statue.post(Runnable {
             tv_statue.text = "下载中"
             ToastUtils.show(baseContext, "下载中")
          })
          Thread.sleep(2000)
          tv_statue.post(Runnable {
             tv_statue.text = "下载完成"
             ToastUtils.show(baseContext, "下载完成")
          })
      }.start()
    

    2. Thread+Handler

    优点
    1. Handler用法简单明了,可以将多个异步任务更新UI的代码放在一起,清晰明了。
    2. 处理单个异步任务代码略显多。
    适用范围
    3. 多个异步任务的更新UI。
    使用示例

    Thread {
        handler.sendEmptyMessage(0)
        Thread.sleep(3000)
        handler.sendEmptyMessage(1)
      }.start()
    ----------------------------------------
        var handler = object : Handler() {
            override fun handleMessage(msg: Message) {
                super.handleMessage(msg)
                when (msg.what) {
                    0 -> {
                        ToastUtils.show(baseContext, "开始下载")
                    }
                    1 -> {
                        ToastUtils.show(baseContext, "下载完成")
                    }
    
                }
    
            }
    
        }
    

    3. AsyncTask

    异步任务 执行完一个,再执行下一个。 在线程池中执行后台任务

    优点

    方便实现异步通信,节省资源
    1. 处理单个异步任务简单,可以获取到异步任务的进度
    2. 可以通过cancel方法取消还没执行完的AsyncTask
    3. 处理多个异步任务代码显得较多
    

    适用范围

    1. 单个异步任务的处理
    

    使用示例

     var time = 3
     val asyncTask: AsyncTask<Int, Int, String?> =
     object : AsyncTask<Int, Int, String?>() {
         override fun doInBackground(vararg params: Int?): String? {
             for (i in params[0]!! downTo 1) {
                try {
                  Thread.sleep(1000)
                  publishProgress(i) //调用onProgressUpdate方法
                 } catch (e: InterruptedException) {
                    e.printStackTrace()
                  }
                }
                 return "计时结束"
              }
    
         override fun onPostExecute(result: String?) {//结束--返回doInBackground里面返回的信息
             super.onPostExecute(result)
               tv_statue.text = result
               Log.i("AsyncTask==","onPostExecute"+result)
            }
    
         override fun onProgressUpdate(vararg values: Int?) {//过程更新
             super.onProgressUpdate(*values)
               tv_statue.text = values[0].toString()
               Log.i("AsyncTask==","onProgressUpdate"+values[0].toString())
               }
           }
         asyncTask.execute(time)
    

    返回:
    AsyncTask==: onProgressUpdate3
    AsyncTask==: onProgressUpdate2
    AsyncTask==: onProgressUpdate1
    AsyncTask==: onPostExecute计时结束

    4.ThreadPoolExecutor

    线程池:可以管理多个线程并行执行
    虽然线程的创建销毁的开销相对较小,但是频繁得创建和销毁也会消耗有限的资源,从而带来性能上的浪费,也不够高效。因此线程池的出现就是为了解决这一问题,即在初始状态创建并维护一定数量的空闲线程,当有需要执行的任务,就交付给线程中的一个线程,任务执行结束后,该线程也不会死亡,而是回到线程池中重新变为空闲状态。

    优点

    减少线程频繁创建销毁的资源开销,同时能够有效控制系统中并发线程的数量,防止系统性能的剧烈下降。
    

    适用范围

    1. 批处理任务
    
    newSingleThreadExecutor

    单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务 这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
    使用示例

      inner class MyThread : Thread() {
            override fun run() {
                super.run()
                var name=currentThread().name
                println(name + "正在执行....");
            }
    
        }
    
    
                    //创建一个可重用固定线程数的线程池
                    val pool: ExecutorService = Executors.newSingleThreadExecutor()
                    //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口;
                    val t1: Thread = MyThread()
                    val t2: Thread = MyThread()
                    val t3: Thread = MyThread()
                    val t4: Thread = MyThread()
                    val t5: Thread = MyThread()
                    //将线程放到池中执行;
                    pool.execute(t1)
                    pool.execute(t2)
                    pool.execute(t3)
                    pool.execute(t4)
                    pool.execute(t5)
                    //关闭线程池
                    pool.shutdown()
    

    返回结果:
    pool-1-thread-1正在执行…
    pool-1-thread-1正在执行…
    pool-1-thread-1正在执行…
    pool-1-thread-1正在执行…
    pool-1-thread-1正在执行…

    newFixedThreadPool

    创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。 线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
    使用示例

                    //创建一个可重用固定线程数的线程池
                    var pool: ExecutorService? =
                        Executors.newFixedThreadPool(3)
                    //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口;
                    val t1: Thread = MyThread()
                    val t2: Thread = MyThread()
                    val t3: Thread = MyThread()
                    val t4: Thread = MyThread()
                    val t5: Thread = MyThread()
                    //将线程放到池中执行;
                    pool.execute(t1)
                    pool.execute(t2)
                    pool.execute(t3)
                    pool.execute(t4)
                    pool.execute(t5)
                    //关闭线程池
                    pool.shutdown()
    

    返回结果:
    pool-2-thread-2正在执行…
    pool-2-thread-3正在执行…
    pool-2-thread-1正在执行…
    pool-2-thread-2正在执行…
    pool-2-thread-3正在执行…

    newCachedThreadPool

    创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
    使用示例

                    //创建一个可重用固定线程数的线程池
                    val pool =
                        Executors.newCachedThreadPool()
                    //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口;
                    val t1: Thread = MyThread()
                    val t2: Thread = MyThread()
                    val t3: Thread = MyThread()
                    val t4: Thread = MyThread()
                    val t5: Thread = MyThread()
                    //将线程放到池中执行;
                    pool.execute(t1)
                    pool.execute(t2)
                    pool.execute(t3)
                    pool.execute(t4)
                    pool.execute(t5)
                    //关闭线程池
                    pool.shutdown()
    

    范湖结果:
    pool-3-thread-4正在执行…
    pool-3-thread-3正在执行…
    pool-3-thread-2正在执行…
    pool-3-thread-5正在执行…
    pool-3-thread-1正在执行…

    newScheduledThreadPool

    大小无限制的线程池,支持定时和周期性的执行线程
    使用示例

      var exec: ScheduledThreadPoolExecutor = ScheduledThreadPoolExecutor(1)
                    exec.scheduleAtFixedRate(
                        Runnable //每隔一段时间就触发异常
                        {
                            // TODO Auto-generated method stub
                            println("111111111111")
                        }, 1000, 5000, TimeUnit.MILLISECONDS
                    )
    
                    exec.scheduleAtFixedRate(
                        Runnable //每隔一段时间打印系统时间,证明两者是互不影响的
                        {
                            // TODO Auto-generated method stub
                            println(System.nanoTime())
                        }, 1000, 2000, TimeUnit.MILLISECONDS
                    )
    

    返回结果:
    111111111111
    23119318857491
    23121319071841
    23129318176148
    23123319007891
    111111111111
    23125318176937
    23127318190359
    111111111111
    23131318344312
    23133318465896
    111111111111
    23135319645812

    5.IntentService

    IntentService继承自Service,是一个经过包装的轻量级的Service,用来接收并处理通过Intent传递的异步请求。客户端通过调用startService(Intent)启动一个IntentService,利用一个work线程依次处理顺序过来的请求,处理完成后自动结束Service。
    IntentService封装了HandlerThread和Handler,但是它继承了Service,所以导致它的优先级比单纯线程要高,所以IntentService适合执行一些高优先级的后台任务。

    特点

    一个可以处理异步任务的简单Service
    当任务执行完后,IntentService 会自动停止,不需要我们去手动结束。
    

    使用示例

    public class MyIntentService extends IntentService {
        private int count = 10;
        private LocalBroadcastManager mLocalBroadcastManager;
    
        public MyIntentService(String name) {
            super(name);
        }
        public MyIntentService() {
            super("someName");// 关键是这句话
        }
        @Override
        public void onCreate() {
            super.onCreate();
            mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
        }
    
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            try {
                Thread.sleep(1000);
                while (count!=0){
                    count--;
                    sendThreadStatus("倒计时中...", count);
                    Thread.sleep(1000);
                }
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
    
        }
        /**
         * 发送进度消息
         */
        private void sendThreadStatus(String status, int progress) {
            Intent intent = new Intent("action.type.thread");
            intent.putExtra("status", status);
            intent.putExtra("progress", progress);
            mLocalBroadcastManager.sendBroadcast(intent);
        }
    
    }
    
    //注册广播--IntentService
            mLocalBroadcastManager = LocalBroadcastManager.getInstance(this)
            mBroadcastReceiver = MyBroadcastReceiver()
            val intentFilter = IntentFilter()
            intentFilter.addAction("action.type.thread")
            mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter)
    
    
    
     /**
         * 非静态内部类,关键字inner
         *可以访问外部类的成员变量
         */
        inner class MyBroadcastReceiver : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent) {
                when (intent.action) {
                    "action.type.thread" -> {
                        //更改UI
                        val progress = intent.getIntExtra("progress", 0)
                        tv_statue.text = progress.toString()
                        if (progress == 0) {
                            tv_statue.text = "下载结束"
                        }
                    }
                }
            }
        }
    
    //开启
     val intent = Intent(this, MyIntentService::class.java)
     startService(intent)
    

    返回结果:
    下载
    9
    8
    7
    6
    5
    4
    3
    2
    1
    下载结束

    参考文献

    Java-线程池 ThreadPool 专题详解 (美团面试题)

    Android多线程的四种方式

    展开全文
  • 安卓线程操作技术

    2014-08-04 17:28:31
    1、安卓线程简介 1.1android线程 当android程序第一次启动时,android系统会启动一个Linux进程和一个主线程。默认的情况下,多数的程序的组件都在该进程和线程中运行。Android会尽量保留一个正在运行的进程,除非...
  • 安卓线程的使用

    2018-08-04 18:05:18
    android中试用线程的几种方式,很简单。求大神指导一下。
  • 安卓线程安全

    千次阅读 2018-07-16 16:20:07
    UI线程安全 ...于是安卓提供了Handler和Looper。 可一个看到一个线程只能有一个Looper和MessageQueue。既然是队列也就是先进先出的顺序结构,由Looper一个个取出。还可看成handler在外面,也就是一...
  • 安卓线程 总结

    2020-05-06 17:53:56
    5、android 创建线程的三种方式 一、继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。 (2)创建Thread子类的...
  • 从java线程到安卓线程

    2015-04-07 23:16:07
    其实在安卓和java中并没有很多不一样,二者使用最大的区别是在安卓中的线程不能直接访问UI,原因我们暂且放在一边,我们先来解决一下在安卓中如何使用线程,让安卓中的线程能够访问UI。 在...
  • 安卓线程问题

    2016-03-12 12:08:52
    )网络请求只能在子线程(backgroundThread)执行,不然会抛异常既然这么划分了,那么就涉及到一个问题,子线程与主线程的通信问题,比如主线程叫子线程完成一件事后告诉我(main),如果使用接口回调,那么调用者...
  • 安卓 内核epoll 机制 注意 两个线程 主线程 线程 1创建一个 pipe 管道 2线程 读管道,没有数据,线程休眠 3主线程得到动作,写管道,写操作导致内核把线程唤醒
  • 27安卓线程

    2016-09-25 19:56:29
    Android 单线程模型 ====================================== *所有的界面显示,用户操作,组件的控制 必须在主线程中执行 Android 线程通信 ============================ *在工作线程中(自己启动的线程)要更新界面...
  • 安卓线程使用问题

    2015-10-15 23:30:00
    笔者今天使用c++ 11的std::thread在安卓设备上来创建线程控制网络异步发送,发现线程启动就马上闪退,估计是安卓设备上不支持c++11的线程库,或者安卓系统版本过低,所以还是用回以前的pthread_create来创建线程...
  • 安卓开发,如果想设置线程优先级有两种方法: 1 Android sdk也提供一个设置线程优先级的方法 2 Thread.java里面提供了设置线程优先级的方法 这两个方法有什么区别,应该选择使用哪一个呢? 二 线程优先级的...
  • 安卓系统或应用开发,java多线程编程是非常重要也是比较难的一个知识点。掌握线程的实现原理、生命周期,合理的使用线程、线程池对于开发稳定、高效的程序是必须的基础。 结合安装系统、应用开发实践,我们先思考...
  • 安卓线程同步方案

    2020-11-04 16:12:47
    } } 问题描述: 有这么一个需求,需要先执行threadRunFirst,然后执行threadRunSecond,要求必须要执行完threadRunSecond以后,threadRunFirst这个线程才可以执行结束,就是要求这两个线程按照预定的顺序执行,可以...
  • 由于Android采用的是单线程模式,开发者无法在子线程中更新 UI,所以系统给我提供了 Handler 这个类来实现 UI 更新问题。 1. Handler 的作用 在Android为了保障线程安全,规定只能由主线程来更新UI信息。而在实际...
  • 在Thread.java类中,有一个枚举类State描述了线程状态机: /** * A thread state. A thread can be in one of the following states: * &lt;ul&gt; * &lt;li&gt;{@link #NEW}&lt;br&...
  • 安卓线程报错

    2016-04-08 09:52:00
    普通打印线程 和 修改UI界面的线程 一个运行成功 一个异常 public class MainActivity extends ActionBarActivity { private Button start_btn = null; private MyThread mythread =null;  @...
  • 读书笔记之安卓线程

    2016-08-25 09:31:16
    安卓线程   安卓的主线程即UI线程,不能做耗时的操作,会出现ANR---应用无响应。那么耗时操作就要在子线程中进行,传统的开启线程方式就是new Thread().start()。其外,还有AsyncTask、IntentService与...
  • 安卓线程的不同写法

    2013-11-27 19:49:31
    线程写法更容易理解,对初学者帮助很大,这里有两种写法可以供大家参考

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,083
精华内容 1,233
关键字:

安卓线程