美文网首页
Android多线程编程

Android多线程编程

作者: 郑在学_blog | 来源:发表于2017-07-15 17:28 被阅读0次

    1.在子线程中更新UI

    Android中更新UI元素,必须在主线程中进行,否则就会出现异常。

    changeBt.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    unbindService(connection);
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            tv1.setText("改变了");
                        }
                    });
    
                }
            });
    

    运行以上程序,你会发现程序果然崩溃了,由此证实Android确实不允许在子线程中进行UI操作。

    使用异步消息处理机制进行UI操作问题。

    public class MainActivity extends AppCompatActivity {
    
        private Button changeBt;
        private TextView tv1;
        private Handler handler = new Handler() {
            public void handleMessage(Message msg) {
                if (msg.what == 1) {
                    tv1.setText("改变了");
                }
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            changeBt = (Button) findViewById(R.id.ChangeButton);
            tv1 = (TextView) findViewById(R.id.Tv1);
            changeBt.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    unbindService(connection);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Message message = new Message();
                            message.what = 1;
                            handler.sendMessage(message);
                        }
                    });
                }
            });
        }
    }
    

    或者使用runOnUiThread()方法,它其实就是一个异步消息处理机制的接口封装,背后的实现原理上面的代码一模一样。

    changeBt.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    unbindService(connection);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            tv1.setText("改变了");
                        }
                    });
    
                }
            });
    

    Android还提供了另外一些好用的工具,比如AsyncTask,它背后的实现原理也是基于异步消息处理机制的,只是Android帮我们做了封装。

    public class DownloadTask  extends AsyncTask<Void,Integer,Boolean>{
        private int i=0;
        private Context con = null;
        ProgressDialog pd1;
    
        DownloadTask(Context con){
            this.con= con;
        }
        @Override
        protected Boolean doInBackground(Void... params) {
           try{
               while(true){
                   int downloadPercent = doDownload();
                   publishProgress(downloadPercent);
                   if(downloadPercent>=100000){
                       break;
                   }
    
               }
           }catch (Exception e){
               return false;
           }
    
            return true;
        }
    
        @Override
        protected void onPreExecute() { 
             pd1 = ProgressDialog.show(con, "提示", "正在下载");
        }
    
        @Override
        protected void onProgressUpdate(Integer... values) {
            pd1.setMessage("Downloaded"+values[0]+"%");
        }
    
        @Override
        protected void onPostExecute(Boolean aBoolean) {
            pd1.dismiss();
            Toast.makeText(con,"下载成功",Toast.LENGTH_SHORT).show();
        }
    
        private int doDownload() {
            for (int j =0;j<10;j++){
                i++;
            }
            return i;
    
        }
    }
    

    AsyncTask是一个抽象类,使用的时候必须继承它,并且我们要为AsyncTask类指定3个泛型参数,第一个是执行AsyncTask传入的参数,可以在后台任务中使用。第二个参数是如果需要在界面上显示当前的进度,以第二个参数的类型作为进度单位。第三个参数是使用这里指定的泛型作为返回值类型。

    • onPreExecute()方法是在后台任务开始执行之前调用。可以用于进行一些界面初始化操作。
    • onInBackground()方法中的所有代码都是在子线程中执行的。任务完成后通过return返回执行结构。但不可以进行UI操作,要进行UI操作可以调用publishProgress()方法。
    • onProgressUpdate()方法,调用了publishProgress()方法后会调用该方法,在onProgressUpdate()方法里可以进行UI操作。
    • onPostExecute()方法是在后台任务执行完,利用返回数据判断进行一些UI操作的。
    • 如果要启动这个任务,需要以下代码:
    new DownloadTask.execute(Context 类型);
    

    2.Service的基本用法

    什么时候需要Service呢?比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的。
    或者可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。

    public class MyService extends Service {
        private DownloadBinder mBinder = new DownloadBinder();
        public MyService() {
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i("MyService","oncreate");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i("MyService","onstartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.i("MyService","ondestroy");
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
         class DownloadBinder  extends Binder {
            public void startDownload(){
                Log.i("Downloadbinder", "startDownload: ");
            }
            public void getprogress(){
                Log.i("Downloadbinder", "getprogress: ");
            }
        }
    }
    
    • onCreate()方法,顾名思义,在服务创建的时候调用。
    • onStartCommand()方法在每次服务启动的时候调用。
    • onDestroy()方法在服务销毁的时候调用。
    • 启动服务的方法
    Intent startIntent = new Intent(MainActivity.this, MyService.class);
    startService(startIntent);
    
    • 暂停服务的方法
    Intent stopIntent = new Intent(MainActivity.this,MyService.class);
    stopService(stopIntent);
    

    -绑定服务和解绑服务

    public class MainActivity extends AppCompatActivity {
    
        private Button changeBt;
        private TextView tv1;
        private MyService.DownloadBinder downloadBinder;
        private ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                downloadBinder = (MyService.DownloadBinder) service;
                downloadBinder.startDownload();
                downloadBinder.getprogress();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            changeBt = (Button) findViewById(R.id.ChangeButton);
            tv1 = (TextView) findViewById(R.id.Tv1);
            Intent startIntent = new Intent(MainActivity.this, MyService.class);
            bindService(startIntent, connection, BIND_AUTO_CREATE);//绑定服务
            changeBt.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    unbindService(connection);//解绑服务
                }
            });
        }
    }
    

    绑定了服务后,可以调用DownloadBinder类里所有public方法。任何一个服务在整个应用程序范围类都是通用的,即Myservice不仅可以和MainActivity绑定,还可以和其他后动绑定。获取到相同的的Binder实例。

    使用IntentService,好处是onHandleIntent已经是在子线程中运行了。服务在运行结束后会自动停止。

    相关文章

      网友评论

          本文标题:Android多线程编程

          本文链接:https://www.haomeiwen.com/subject/jltzhxtx.html