多线程和服务组件Service的基本使用

为了保证App运行的流畅性,大部分耗时操作,比如文件的读/写,网络的请求等都不能放在主线程来实现,而是需要另开线程或者通过开启服务组件放在后台执行.

多线程

使用多线程也可以实现类似后台服务的功能.Android中有三种实现多线程的方式.

匿名类

通过Thread类可以开启一个线程, Runnable接口中的方法run,会在调用start方法开启线程后执行.

 //1匿名类
   new Thread(new Runnable() {
       @Override
       public void run() {
           Log.i("Thread", "run: " + "Thread");
       }
   }).start();

实现接口类

让TestThread类实现接口,然后传入开启的线程testThread.

public class TestThread implements Runnable {
    @Override
    public void run() {
        Log.i("TestThread", "run: " + "TestThread");
    }
}

TestThread testThread = new TestThread();
new Thread(testThread).start();

继承Thread类

让子类SonThread继承Thread,并实现run方法.

public class SonThread extends Thread {
    @Override
    public void run() {
        Log.i("SonThread", "run: " + "SonThread");
    }
}

SonThread sonThread = new SonThread();
sonThread.start();

子线程注意事项

通过Thread开启的子线程可以处理逻辑或数据操作,但是却不能更新UI.只有在主线程(original thread)中,才可以更新UI.不同线程间的通信可以通过Handler类或者AsyncTask类来实现.

异步消息处理机制

Handler

private TextView textView;
public static final int UPDATE_TEXT = 1;
private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what){
            case 1:
                textView.setText("Hello world!");
                break;
            default:
                break;
        }
    }
};

new Thread(new Runnable() {
    @Override
    public void run() {
        Message msg = new Message();
        msg.what = UPDATE_TEXT;
        handler.sendMessage(msg);
    }
}).start();

当子线程完成任务后,通过Handler类发送带有参数的消息Message.然后handler接收到消息后,可以调用接口handleMessage来更新UI.

Hander处理异步消息,通过Message,MessageQueue,Looper来实现.MessageQueue相当于一个容器,用于存储线程中的Message消息.线程开启后,Looper会调用自身的loop方法,不断检测线程中的Message消息,发现后就会加入到MessageQueue中,可以把它看做MessageQueue的管家.Hander会根据Looper将Message加入MessageQueue的顺序,在主线程中进行处理.

AsyncTask

public class DownloadTask extends AsyncTask<Void, Integer, Boolean> {

    private ProgressBar progressBar;
    private Context context;

    public DownloadTask(ProgressBar progressBar, Context context){
        this.progressBar = progressBar;
        this.context = context;
    }
    @RequiresApi(api = Build.VERSION_CODES.O)

    @Override
    protected void onPreExecute() {
        progressBar.setMin(0);
        progressBar.setMax(10000);
        progressBar.setProgress(0);
        progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    protected Boolean doInBackground(Void... voids) {
        int progress = 0;
        try{
            while (progress < 10000){
                progress += 1;
                publishProgress(progress);
            }
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }

        return true;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        progressBar.setProgress(values[0]);
    }

    @Override
    protected void onPostExecute(Boolean aBoolean) {
        progressBar.setVisibility(View.INVISIBLE);

        if (aBoolean){
            Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show();
        }else {
            Toast.makeText(context, "Failure", Toast.LENGTH_SHORT).show();
        }
    }
}
//调用
new DownloadTask(progressBar, this).execute();

AsyncTask有三个泛型,第一个代表执行任务时参数类型,第二个是执行过程中的进度,最后一个是执行结果. 在onPreExecute方法中做一些执行任务前的辅助工作; doInBackground方法用于处理耗时逻辑,执行的进度progress可以通过调用publishProgress方法传出,然后就会调用onProgressUpdate方法;在onProgressUpdate可以更新UI,显示在界面上;任务执行完毕后,会调用onPostExecute方法来返回任务执行的结果.

使用服务

服务类似子线程,可以很方便的处理耗时操作.

定义

public class TestService extends Service {
    public TestService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

继承至Service,实现抽象方法onBind.其中onCreate方法在服务被创建时执行,一个服务只能执行一次;onStartCommand在Service被调用时执行,可以反复调用多次; onDestroy方法在服务被停止时调用,一个服务也只能调用一次.

调用

正确调用Service,首先需要在AndroidManifest中的Application标签中进行注册.

<service android:name=".TestService"
            android:enabled="true"
            android:exported="true"></service>

通过Intent可以很方便的开启和关闭服务.

public void startService(View view){
    Intent startIntent = new Intent(this, MyService.class);
    startService(startIntent);
}
public void stopService(View view){
    Intent stopIntent = new Intent(this, MyService.class);
    stopService(stopIntent);
}

通过Service的前台服务,可以让App运行的信息始终显示在手机通知栏中.

@Override
public void onCreate() {
    super.onCreate();
    Log.i("MyService", "onCreate: " + "MyService");
    Intent intent = new Intent(this, MainActivity.class);
    PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
    Notification notify = new NotificationCompat.Builder(this)
            .setContentTitle("This is title")
            .setContentText("This is text")
            .setWhen(System.currentTimeMillis())
            .setSmallIcon(R.mipmap.ic_launcher)
            .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
            .setContentIntent(pi)
            .build();
    startForeground(1, notify);
}

通过IBinder在Activity和Service中进行通信

class MyBinder extends Binder {
    public void startDownload(){
        Log.i("startDownload", "startDownload");
    }
    public int getProgress(){
        Log.i("getProgress", "getProgress");
        return 0;
    }
}
private MyBinder myBinder = new MyBinder();

@Override
public IBinder onBind(Intent intent) {
    return myBinder;
}

修改MyService中IBinder的实现,并添加内部类MyBinder.然后可以在MainActivity通过ServiceConnection调用MyBinder中的方法.

private MyService.MyBinder downloadBinder;
//通过serviceConnection可以获取服务的Binder, 然后调用Binder中的方法;
private ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) 
        downloadBinder = (MyService.MyBinder)iBinder;
        downloadBinder.startDownload();
        downloadBinder.getProgress();
    }
    @Override
    public void onServiceDisconnected(ComponentName componentName) {
    }
};
public void bindService(View view){
    Intent bindIntent = new Intent(this, MyService.class);
    bindService(bindIntent, serviceConnection, BIND_AUTO_CREATE);
}
public void unbindService(View view){
    Intent bindIntent = new Intent(this, MyService.class);
    unbindService(serviceConnection);
}

销毁的三种方式

  1. 通过startService启动的服务,可以通过stopService的方式销毁.通过bindService启动的服务,可以通过unbindService的方式销毁.这两种方式,都会调用服务的onDestroy方法.如果在活动中既调用startService又调用bindService,那么就需要同时调用两者的停止方法来销毁.

2.在服务的执行方法onStartCommand调用stopSelf()方法.

3.让服务继承至IntentService.这样当服务中的onStartCommand方法执行完毕,会自动销毁.

总结

多线程和服务的存在,让一个App在运行期间,可以同时处理多个任务,保证了界面运行的流畅性.通过Thread类开启线程,将任务放在线程的run方法中.用Handle类和AsyncTask类可以实现子线程与主线程的通信.服务类似新开一个进程,通过Activity开启后会一直存在,直到调用stopSelf方法或者相应的关闭方法.为了防止服务忘记关闭或者关闭失败造成的资源浪费,可以让服务继承IntentService类.这样开启的服务,在任务执行完毕后会自动停止.

    原文作者:uniapp
    原文地址: https://www.jianshu.com/p/6754a030f662
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞