赞
踩
1.每一个app就是一个进程,进程开启的时候默认就有一个主线程(UI线程)
2.线程之间可以做到数据共享,但是进程之间无法直接进行数据共享(但可通过组件进行)
3.主线程才能进行UI更新的操作
4.不要把耗时操作放在主线程,而是开启一个子线程去处理这些事情
下面介绍两种常用的方法来创建子线程,这两种方法都是基于Java的多线程来实现的。
步骤1:
编写子线程类,这里可以使用内部类,方便共享数据
/** * 继承Thread类开启子线程 */ class SonThread extends Thread { /* * 自定义方法,run方法调用,使得run方法更加简洁 */ protected int CountSum() { for (int i = 0; i < 1000; i++) { sum += 1; } return sum; } /** * 重写run方法 * 在run方法中调用子线程需要执行的方法 */ @Override public void run() { super.run(); CountSum(); tv_log.setText(sum+""); } }
步骤2
通过start方法开启子线程
Thread mThread = new SonThread();
// 注意不是使用run方法来开启线程,而是使用start方法
// 直接使用run方法的话还是在主线程中运行
mThread.start();
(考虑到Java的单继承,更加推荐此方法)
步骤1:
编写子线程类实现Runnable方法
class SonThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
sum += 1;
}
Log.d("zhiqiang","当前运行线程ID:"+Thread.currentThread().getId());
tv_log.setText(sum+"");
}
}
步骤2:
通过Thread的构造方法来构造Thread对象,并通过start方法开启子线程
Thread mThread = new Thread(new SonThread());
mThread.start();
注意,开启多个子线程,子线程的执行顺序与代码顺序无关
为了用户体验的流畅,安卓禁止在子线程中更新UI,在子线程直接更新UI会导致崩溃(某些情况下不会崩溃??但是还是要按照规范只在主线程中更新UI)。
下面介绍最为基础的方式----通过Handler来实现子线程间接更新UI的方法:
步骤1:
构建类,继承Handler类,实现handleMessage方法
// 类属性
protected static final int CHANGE_TEXT_MAG = 1;
protected class UIHandler extends Handler{
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case CHANGE_TEXT_MAG:
// 实现更新UI的操作
tv_log.setText(msg.arg1+"");
break;
}
}
}
步骤2:
在主线程对Handler初始化
// 声明Handler类对象
private UIHandler uiHandler;
// 初始化Handler对象
uiHandler = new UIHandler();
Handler对象在那个线程中创建的,其中的方法就会在那个线程中执行
步骤3:
在子线程中创建Message类,向Handler发送消息
// 向Handler发送消息
Message message = new Message();
message.what = CHANGE_TEXT_MAG;
message.arg1 = sum;
uiHandler.sendMessage(message);
使用上一节中的方法完成子线程更行UI操作太过麻烦,使用AsyncTask框架,能够省去繁琐的Handler线程切换。
步骤:1
编写类,继承AsyncTask类,并实现必要的方法
// 使用框架更新UI protected class DownloadTask extends AsyncTask<String,Integer,Boolean>{ // 需要提前准备的任务,在doInBackground之前运行 @Override protected void onPreExecute() { super.onPreExecute(); Log.d("zhiqiang","运行--onPreExecute方法"); } // 后台需要进行的操作,这也是最主要的方法 ** @Override protected Boolean doInBackground(String... strings) { String data = strings[0]; Log.d("zhiqiang","接受参数"+data+"\n开始执行doInBackground方法"); int prograss = 0; while (prograss < 100){ prograss += 10; // 通过publishProgress方法通知主进程当前线程进度 publishProgress(prograss); Log.d("zhiqiang","当前下载进度:"+prograss); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } // 主线程运行过程中,使用该方法接受子线程运行进度(与publishProgress方法配合使用,通知一次,接收一次) @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); int progress = values[0]; tv_log.setText("下载进度:"+progress); } // 子线程任务结束会调用该方法(doInBackground方法结束时调用) @Override protected void onPostExecute(Boolean aBoolean) { super.onPostExecute(aBoolean); tv_log.setText("下载完成!!"); } }
Java包上右键 > New > Service > Service
// onCreate方法只会在初次创建的时候被调用(销毁之后再创建也会被调用)
@Override
public void onCreate() {
super.onCreate();
}
// onStartCommand方法每次调用startService方法的时候都会被调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
// 使用stopService方法销毁Service的时候会调用onDestroy方法
@Override
public void onDestroy() {
super.onDestroy();
}
通过startService和stopService来创建和关闭Service
// 1 > 使用Service创建Intent
Intent intent = new Intent(MainActivity.this,MyService.class);
// 2 > 调用startService方法传递Intent来开启Service
startService(intent);
/*在调用stopService方法之前再次调用startService方法,不会触发Service的onCreate方法*/
// 3 > 停止Service
stopService(intent);
通过bindService和unBindService来创建和关闭Service,这种方式创建的Service可以和很方便Activity进行通信
/* 1 > 编写类继承Binder类,并通过Service的onBind方法返回该类的实体对象*/ public class MyBinder extends Binder{ private int sum = 0; public void Count(int num1,int num2){ sum = num1 + num2; } public int getSum(){ return sum; } } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return new MyBinder(); }
// 2 > 使用Service创建Intent
Intent intent = new Intent(MainActivity.this,MyService.class);
// 3 > 在Activity中调用bindService方法,连接Service
bindService(intent,connection,BIND_AUTO_CREATE);
// 4 > 初始化Binder对象,在connection中对其进行赋值 private MyService.MyBinder mBinder = null; // 5 > bindService方法中的connection参数需要手动编写ServiceConnection类 private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 其中的参数service为连接的service中onBind方法返回的Binder对象 mBinder = (MyService.MyBinder)service; // 调用service中bind类返回的方法 mBinder.Count(1,2); } @Override public void onServiceDisconnected(ComponentName name) { // 一般在Activity与Service被动非正常断开连接的时候,重新连接Service会被调用。。 } };
// 6 > 使用unbindService方法,传递connection为参数,断开与Service的连接
unbindService(connection);
bindService和stopService,只会在第一次调用bindService的时候会调用bindService和onCreate方法,调用stopService的时候会调用onDestroy方法。不会调用onStartCommand方法
Service默认运行在主线程中,若想要在Service中运行耗时操作,需要手动创建子线程。
通过前台Service,service会在通知中显示,并且在Activity不可见的时候,继续在后台执行。
步骤1:
在AndroidManifest.xml配置文件中添加permission
<manifest ...>
<!--添加下方uses-permission配置-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
...
<application ...>
...
</manifest>
步骤2:
编写Service,在适当的生命周期方法中将Service挂载到Notification上
public class MyService extends Service{ ... @Override public int onStartCommand(Intent intent, int flags, int startId) { // 开启前台Service NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ NotificationChannel channel = new NotificationChannel("LearnService", "LearnService",NotificationManager.IMPORTANCE_DEFAULT); manager.createNotificationChannel(channel); } // 定义点击通知后跳转的Activity Intent mIntent = new Intent(MyService.this,MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(MyService.this,0,mIntent,0); // 生成通知 Notification notification = (new NotificationCompat.Builder(MyService.this,"LearnService")) .setContentTitle("setContentTitle") .setContentText("setContentText") .setSmallIcon(R.drawable.ic_launcher_background) .setContentIntent(pendingIntent) .build(); // 关键步骤 startForeground(1,notification); return super.onStartCommand(intent, flags, startId); }
这样,通过Activity调用startService方法开启Service的时候,就会生成一个Service的通知了。该Service在退出App的时候不会一起关闭
后台调用的Service,会自动创建子线程,且运行完会被自动回收
public class MyService extends IntentService {
也可以使用普通Service每次调用stopSelf,但是需要添加子线程。。
步骤1:
创建继承IntentService
再Java包上右键 > Service > Service(IntentService) 来创建 IntentService
步骤2:
在onHandleIntent方法中编写子线程中需要执行的操作
步骤2:
在Activity中调用启动IntentService
Intent intent = new Intent(MainActivity.this,MyIntentService.class);
startService(intent);
IntentService中子线程的任务完成之后,回自动的调用Destroy方法,结束子线程。而普通的Service创建子线程运行结束之后,不会自动关闭子线程
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。