Android Service、IntentService,Service和组件间通信

Service组件

Service 和Activity 一样同为Android 的四大组件之一,并且他们都有各自的生命周期,要想掌握Service 的用法,那就要了解Service 的生命周期有哪些方法,并且生命周期中各个方法回调的时机和作用

什么是service?service的基本概念

Service是Android中实现程序后台运行的解决方案,非常适合用于去执行哪些不需要和用户交互而且还要求长期运行的任务。不能运行在一个独立的进程当中,而是依赖与创建服务时所在的应用程序进程。只能在后台运行,并且可以和其他组件进行交互。

Service可以在很多场合使用,比如播放多媒体的时候用户启动了其他Activity,此时要在后台继续播放;比如检测SD卡上文件的变化;比如在后台记录你的地理信息位置的改变等等,总之服务是藏在后台的。

定义(启动)一个Service

Service 有两种启动方式,并且它的两种启动方式的生命周期是不一样的。

1.startService方式启动Service

当应用组件通过startService方法来启动Service 时,Service 则会处于启动状态,一旦服务启动,它就会在后台无限期的运行,生命周期独立于启动它的组件,即使启动它的组件已经销毁了也不受任何影响,由于启动的服务长期运行在后台,这会大量消耗手机的电量,因此,我们应该在任务执行完成之后调用stopSelf()来停止服务,或者通过其他应用组件调用stopService 来停止服务。

startService 启动服务后,会执行如下生命周期:onCreate() -> onStartCommand() -> onStart()(现在已经废弃) -> onDestroy() 。具体看一下它的几个生命周期方法:

  • onCreate() :首次启动服务的时候,系统会调用这个方法,在onStartCommand 和 onBind 方法之前,如果服务已经启动起来了,再次启动时,则不会调用此方法,因此可以在onCreate 方法中做一些初始化的操作,比如要执行耗时的操作,可以在这里创建线程,要播放音乐,可以在这里初始化音乐播放器。

  • onStartCommand(): 当通过startService 方法来启动服务的时候,在onCreate 方法之后就会回调这个方法,此方法调用后,服务就启动起来了,将会在后台无限期的运行,直到通过stopService 或者 stopSelf 方法来停止服务。

  • onDestroy():当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用。  

了解了这几个生命周期方法后,就来写一个简单Service 。

要使用Service 就要通过继承Service类(或者继承IntentService ,后文会讲)来实现,代码如下:

package com.example.servicetest;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;public class MyService extends Service {  public static final String TAG = "MyService";  //创建服务时调用
    @Override  public void onCreate() {  super.onCreate();  Log.d(TAG, "onCreate");  }  //服务执行的操作
    @Override  public int onStartCommand(Intent intent, int flags, int startId) {  Log.d(TAG, "onStartCommand");  return super.onStartCommand(intent, flags, startId);  }  //销毁服务时调用
    @Override  public void onDestroy() {  super.onDestroy();  Log.d(TAG, "onDestroy");  }  @Override  public IBinder onBind(Intent intent) {  return null;  }  
}

可以看到,我们只是在onCreate()、onStartCommand()和onDestroy()方法中分别打印了一句话,并没有进行其它任何的操作,注意代码注释中这三个方法的作用。

onBind()方法是Service中唯一的一个抽象方法,所以必须要在子类里实现。我们知道,Service可以有两种启动方式:一种是startService(),另一种是bindService()。第二种启动方式才会用到onBind()方法。我们这先用第一种方式启动Service,所以暂时忽略onBind()方法。

(2)在清单文件中声明:(和Activity标签并列)

<service android:name=".MyService">        </service>

(3)修改activity_main.xml代码,如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical" >  <Button  android:id="@+id/button1_start_service"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:text="Start Service" />  <Button  android:id="@+id/button2_stop_service"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:text="Stop Service" />  </LinearLayout>

 

我们在布局文件中加入了两个按钮,一个用于启动Service,一个用于停止Service。

(4)在MainActivity作为程序的主Activity,在里面加入启动Service和停止Service的逻辑,代码如下:

package com.example.servicetest;import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;public class MainActivity extends Activity implements OnClickListener {  private Button button1_start_service;  private Button button2_stop_service;  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  button1_start_service = (Button) findViewById(R.id.button1_start_service);  button2_stop_service = (Button) findViewById(R.id.button2_stop_service);  button1_start_service.setOnClickListener(this);  button2_stop_service.setOnClickListener(this);  }  @Override  public void onClick(View v) {  switch (v.getId()) {  case R.id.button1_start_service:  Intent startIntent = new Intent(this, MyService.class);  startService(startIntent);  break;  case R.id.button2_stop_service:  Intent stopIntent = new Intent(this, MyService.class);  stopService(stopIntent);  break;  default:  break;  }  }  }

代码所示,在Start Service按钮的点击事件里,我们构建出了一个Intent对象,并调用startService()方法来启动MyService。然后在Stop Serivce按钮的点击事件里,我们同样构建出了一个Intent对象,并调用stopService()方法来停止MyService。代码的逻辑非常简单。

小结:通过startService 方式启动的服务,服务会无限期的在后台运行,直到通过stopService 或 stopSelf 来终止服务。服务独立于启动它的组件,也就是说,当组件启动服务后,组件和服务就再也没有关系了,就算启动它的组件被销毁了,服务照样在后台运行。通过这种方式启动的服务不好与组件之间通信。

bindService 方式启动服务

除了startService 来启动服务之外,另外一种启动服务的方式就是通过bindService 方法了,也就是绑定服务,其实通过它的名字就容易理解,绑定即将启动组件和服务绑定在一起。前面讲的通过startService 方式启动的服务是与组件相独立的,即使启动服务的组件被销毁了,服务仍然在后台运行不受干扰。但是通过bindSerivce 方式绑定的服务就不一样了,它与绑定组件的生命周期是有关的。如下:

多个组件可以绑定到同一个服务上,如果只有一个组件绑定服务,当绑定的组件被销毁时,服务也就会停止了。如果是多个组件绑定到一个服务上,当绑定到该服务的所有组件都被销毁时,服务才会停止。

bindService 绑定服务 和startService 的生命周期是不一样,bindServie 的生命周期如下:onCreate -> onBind -> onUnbind ->onDestroy。其中重要的就是onBind 和onUnbind 方法。

  • onBind(): 当其他组件想通过bindService 与服务绑定时,系统将会回调这个方法,在实现中,你必须返回一个IBinder接口,供客户端与服务进行通信,必须实现此方法,这个方法是Service 的一个抽象方法,但是如果你不允许绑定的话,返回null 就可以了。

  • onUnbind(): 当所有与服务绑定的组件都解除绑定时,就会调用此方法。

了解了这2个方法后,我们来看一下怎么绑定一个服务。
1,首先,添加一个类 继承 Binder ,在Binder 类中添加其他组件要与服务交互的方法,并在onBind() 方法中返回IBinder 实例对象:

public class SimpleService extends Service {public static final String TAG = "SimpleService";@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG,"call onBind...");//返回IBinder 接口对象return new MyBinder();}@Overridepublic boolean onUnbind(Intent intent) {Log.i(TAG,"call onUnbind...");return super.onUnbind(intent);}@Overridepublic void onCreate() {Log.i(TAG,"call onCreate...");}@Overridepublic void onStart(Intent intent, int startId) {Log.i(TAG,"call onStart...");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG,"call onStartCommand...");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {Log.i(TAG,"call onDestroy...");}// 添加一个类继承Binderpublic  class MyBinder extends Binder{// 添加要与外界交互的方法public String  getStringInfo(){return "调用了服务中的方法";}}}

2, 绑定服务的时候,需要提供一个ServiceConnection 接口,在接口回调中获取Binder 对象,与服务进行通信。

 private SimpleService.MyBinder mMyBinder;// 绑定/解除绑定 Service 回调接口private ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 绑定成功后回调//1 ,获取Binder接口对象mMyBinder = (SimpleService.MyBinder) service;//2, 从服务获取数据String content = mMyBinder.getStringInfo();// 3,界面提示Toast.makeText(ServiceSimpleActivity.this,content,Toast.LENGTH_LONG).show();}@Overridepublic void onServiceDisconnected(ComponentName name) {// 解除绑定后回调mMyBinder = null;}};

3,绑定和解除绑定服务

            case R.id.bind_service:Intent intent = new Intent(this,SimpleService.class);// 绑定服务
                bindService(intent,mConnection, Context.BIND_AUTO_CREATE);break;case R.id.unbind_service:// 解除绑定服务
                unbindService(mConnection);break;

可以看到,绑定服务的生命周期内依次调用了onCreate ,onBind,onUnbind 和 onDestroy 方法,只有中间两个生命周期方法与startService 启动服务是不同的。

两种方式的生命周期的异同:

         Service生命周期.png

started服务与bind服务的区别:

区别一:生命周期

  • 通过started方式的服务会一直运行在后台,需要由组件本身或外部组件来停止服务才会以结束运行
  • bind方式的服务,生命周期就要依赖绑定的组件

区别二:参数传递

  • started服务可以给启动的服务对象传递参数,但无法获取服务中方法的返回值
  • bind服务可以给启动的服务对象传递参数,也可以通过绑定的业务对象获取返回结果

实际开发中的技巧;

  • 第一次先使用started方式来启动一个服务
  • 之后可以使用bind的方式绑定服务,从而可以直接调用业务方法获取返回值

IntentService

IntentService 是Service 的子类,它使用工作线程逐一处理所有启动请求,果您不要求服务同时处理多个请求,这是最好的选择。 您只需实现 onHandIntent方法即可,该方法会接收每个启动请求的 Intent,使您能够执行后台工作。

IntentService 示例

IntentService 默认为我们开启了一个工作线程,在任务执行完毕后,自动停止服务,因此在我们大多数的工作中,使用IntentService 就够了,并且IntentService 比较简单,只要实现一个方法OnHandleIntent,接下来看一下示例:

(1)新建一个MyIntentService类,继承自IntentService,并重写父类的onHandleIntent()方法,代码如下:

复制代码
 1 package com.example.servicetest;2 3 import android.app.IntentService;4 import android.content.Intent;5 import android.util.Log;6 7 public class MyIntentService extends IntentService{8 9     public MyIntentService() {
10         super("MyIntentService");//调用父类有参构造函数。这里我们手动给服务起个名字为:MyIntentService
11         // TODO Auto-generated constructor stub
12     }
13 
14     //该方法在会在一个单独的线程中执行,来完成工作任务。任务结束后,该Service自动停止
15     @Override
16     protected void onHandleIntent(Intent intent) {
17         // TODO Auto-generated method stub
18         for(int i = 0;i<3;i++) {
19             //打印当前线程的id
20             Log.d("MyIntentService","IntentService线程的id是:"+Thread.currentThread().getId());
21             try {
22                 Thread.sleep(1000);
23             } catch (InterruptedException e) {
24                 // TODO Auto-generated catch block
25                 e.printStackTrace();
26             }
27         }        
28     }
29 
30     @Override
31     public void onDestroy() {
32         // TODO Auto-generated method stub
33         super.onDestroy();
34         Log.d("MyIntentService","onDestroy");
35     }
36 }
复制代码

这里首先要提供一个无参的构造方法,并且必须在其内部调用父类的有参构造方法(9至12行),我们在第10行手动将服务的名字改为“MyIntentService”。

然后在子类中实现onHandleIntent()这个抽象方法,可以在这个方法里去处理一些具体的逻辑,我们就用三次for循环,打印当前线程的id,每次延时1秒。

因为这个服务在运行结束后会自动停止,所以我们在onDestroy()方法中打印日志验证一下。

(2)在清单文件中对服务进行注册服务:

<service android:name=".MyIntentService"> </service>

(3)在activity_main.xml中添加一个按钮button3_stop_intentservice,用于启动MyIntentService服务,代码略。

(4)在MainActivity里面加入启动IntentService的逻辑,核心代码如下:

1       case R.id.button3_stop_intentservice:
2             Log.d("MainActivity","主线程的id是:"+Thread.currentThread().getId());
3             Intent intentService = new Intent(this,MyIntentService.class);
4             startService(intentService);
5         default:

我们在第02行中,打印主线程的id。

运行程序,点击按钮button3_stop_intentservice,显示如下:

由此可见,启动一个IntentService和启动一个普通的Service,步骤是一样的。

4、Service和Thread的关系:

不少Android初学者都可能会有这样的疑惑,Service和Thread到底有什么关系呢?什么时候应该用Service,什么时候又应该用Thread?答案可能会有点让你吃惊,因为Service和Thread之间没有任何关系!

之所以有不少人会把它们联系起来,主要就是因为Service的后台概念。Thread我们大家都知道,是用于开启一个子线程,在这里去执行一些耗时操作就不会阻塞主线程的运行。而Service我们最初理解的时候,总会觉得它是用来处理一些后台任务的,一些比较耗时的操作也可以放在这里运行,这就会让人产生混淆了。但是,如果我告诉你Service其实是运行在主线程里的,你还会觉得它和Thread有什么关系吗?

其实,后台和子线程是两个完全不同的概念:

Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现。你可能又会问,Service既然是运行在主线程里,在这里一直执行着心跳连接,难道就不会阻塞主线程的运行吗?当然会,但是我们可以在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。

既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建呢?这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例;而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。

所以说,一个比较标准的Service,就可以写成本段中第1节的样子。

IntentService总结:IntentService是Service 的子类,默认给我们开启了一个工作线程执行耗时任务,并且执行完任务后自 动停止服务。扩展IntentService比较简单,提供一个构造方法和实现onHandleIntent 方法就可了,不用重写父类的其他方法。但是如果要绑定服务的话,还是要重写onBind 返回一个IBinder 的。使用Service 可以同时执行多个请求,而使用IntentService 只能同时执行一个请求。

Service 与应用组件通信的几种方式

1,BroadcastReceiver
通过前文我们知道,startService方式启动的服务在后台,无限期地运行,并且与启动它的组件是独立的,启动Service 之后也就与启动它的组件没有任何关系了。因此它是不能与启动它的组件之间相互通信的。虽然Service 没有提供这种启动方式的通信方法,我们还是可以通过其他方式来解决的,这就用到了BroadcastReceiver。

场景描述:通过startService 启动一个长期在后台运行的下载图片服务,然后在界面上点击下载按钮,通过intent 传递一个下载链接给Service,在下载完成后,通过BroadcastReceiver 通知Activity 界面显示图片。看一下代码实现:

Service代码如下:

public class DownloadService extends Service {public static final String IMAGE = "iamge_url";public static final String RECEIVER_ACTION = "com.zhouwei.simpleservice";private static final String TAG = "DownloadService";public static final String ACTION_START_SERVICER = "com.zhouwei.startservice";public static final String ACTION_DOWNLOAD = "com.zhouwei.startdownload";private Looper mServiceLooper;private ServiceHandler mServiceHandler;private final class ServiceHandler extends Handler {public ServiceHandler(Looper looper){super(looper);}@Overridepublic void handleMessage(Message msg) {// 工作线程做耗时下载String url = (String) msg.obj;Bitmap bitmap = null;try {bitmap = Picasso.with(getApplicationContext()).load(url).get();Intent intent = new Intent();intent.putExtra("bitmap",bitmap);intent.setAction(RECEIVER_ACTION);// 通知显示
                LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);} catch (IOException e) {e.printStackTrace();}//工作完成之后,停止服务
            stopSelf();}}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {// 开启一个工作线程做耗时工作HandlerThread thread = new HandlerThread("ServiceHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);thread.start();// 获取工作线程的LoopermServiceLooper = thread.getLooper();// 创建工作线程的HandlermServiceHandler = new ServiceHandler(mServiceLooper);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG,"call onStartCommand...");if(intent.getAction().equals(ACTION_DOWNLOAD)){handleCommand(intent);}else if(intent.getAction().equals(ACTION_START_SERVICER)){//do nothing
        }return START_STICKY;}private void handleCommand(Intent intent){String url = intent.getStringExtra(IMAGE);// 发送消息下载Message message = mServiceHandler.obtainMessage();message.obj = url;mServiceHandler.sendMessage(message);}
}

新建了一个DownloadService ,在里面启动了一个工作线程,在线程里下载图片,然后通过BroadcastReceiver 通知Activity显示。

Activity的代码很简单,注册BroadcastReceiver,在onReceiver中显示图片就好了,代码如下:

private ImageView mImageView;private BroadcastReceiver mReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {// 显示图片Bitmap bitmap = intent.getParcelableExtra("bitmap");mImageView.setImageBitmap(bitmap);}};/*** 启动下载*/private void startDownload(){Intent intent = new Intent(this,DownloadService.class);// 启动服务intent.putExtra(DownloadService.IMAGE,"http://www.8kmm.com/UploadFiles/2012/8/201208140920132659.jpg");intent.setAction(DownloadService.ACTION_DOWNLOAD);startService(intent);}

 

 

 

 

 

 

 

 

 

 

声明

https://blog.csdn.net/qq_34115898/article/details/83347882

文章来源

转载于:https://www.cnblogs.com/ythzxxq/p/9978158.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366624.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

生物计算机科学家,科学家开发细胞计算机 人体就是一台大型计算机

原标题&#xff1a;科学家开发细胞计算机 人体就是一台大型计算机欢迎收看新一期“新奇榜”&#xff0c;新鲜科技、奇闻怪事尽在新奇榜。近日&#xff0c;瑞士研究人员成功制造出了一种功能强大、类似计算机的人体细胞。这种细胞可能被用来帮助监测一个人的健康状况&#xff0c…

k8s源码分析 pdf_rook源码分析之一:rook架构解析

rook简介Rook是一款云原生环境下的开源分布式存储编排系统&#xff0c;目前支持 Ceph、NFS、Edegefs、Cassandra、CockroachDB等存储系统。它实现了一个自动管理的、自动扩容的、自动修复的分布式存储服务。Rook 支持自动部署、启动、配置、分配、扩容/缩容、升级、迁移、灾难恢…

weex eros框架源码解析

weex eros是基于alibaba weex框架进行二次封装的客户端跨平台开发框架&#xff0c;主要是为前端开发者&#xff08;可以不用熟悉客户端开发)提供的一站式客户端app开发解决方案。官网地址为&#xff1a;https://bmfe.github.io/eros-docs/#/。为了方便前端开发者和客户端开发者…

多选一的图片和文字

利用 radio 做单选事件&#xff0c;js 兄弟选择 nextSibling 获取邻近的图片对象&#xff0c;然后进行改变 例子&#xff1a; CSS <style type"text/css">input[type"radio"] {display: none;}label{font-size: 16px;}.choose_or{width: 1.2rem;heig…

【每日一题】收集足够苹果的最小花园周长

文章目录 Tag题目来源解题思路方法一&#xff1a;二分枚举答案 写在最后 Tag 【二分枚举答案】【二维网格】【2023-12-24】 题目来源 1954. 收集足够苹果的最小花园周长 解题思路 方法一&#xff1a;二分枚举答案 思路 通过如下过程&#xff0c;我们可以求出边长为 2n 时&…

小数前的0在html不显示,jsp小数显示问题 例如 我在oracle 数据库中查询出来的是 0.01 但是在jsp页面上就显示成 .01 没有前面的0...

满意答案1234junling2013.08.28采纳率&#xff1a;56% 等级&#xff1a;12已帮助&#xff1a;6022人控制保留几位有效小数的js函数//Code CreateBy abandonship 2007.03.12function FormatAfterDotNumber( ValueString, nAfterDotNum ){var ValueString,nAfterDotNum ;var r…

Jira filter subscribe issues

Jira & filter & subscribe & issues https://confluence.atlassian.com/search/?querysubscribeissues&productNameJiraCore&productVersion7.3]https://confluence.atlassian.com/jiracoreserver073/saving-your-search-as-a-filter-861257224.html 转载…

iView 一周年了,同时发布了 2.0 正式版,但这只是开始...

两年前&#xff0c;我开始接触 Vue.js 框架&#xff0c;当时就被它的轻量、组件化和友好的 API 所吸引。之后我将 Vue.js 和 Webpack 技术栈引入我的公司&#xff08;TalkingData&#xff09;可视化团队&#xff0c;并经过一年多的实践&#xff0c;现已成为整个公司的前端开发规…

Hawtio和Apache JClouds

介绍 我最近花了一些时间为Hawtio开发 Apache Jclouds插件。 尽管还有很多待完成的工作&#xff0c;但我无法激动&#xff0c;想分享…… 这个Hawtio到底是什么&#xff1f; 每当我注意到一个很酷的开源项目时&#xff0c;我通常都会订阅邮件列表&#xff0c;以便我可以更好地…

【转】安全加密(一):这些MCU加密方法你都知道吗?

本文导读 随着物联网和边缘计算的出现&#xff0c;五花八门的MCU也被应用其中&#xff0c;如何保证我们的程序安全和知识产权不受侵犯呢&#xff0c;本文我们将对主流MCU的程序加密进行讲解&#xff0c;希望能够帮助你选择最适合自己应用的微处理器。 1. MCU加密 通常所说的MC…

浅谈Vue内置component组件的应用场景

官方的说明 渲染一个“元组件”为动态组件。依 is 的值&#xff0c;来决定哪个组件被渲染。 <!-- 动态组件由 vm 实例的属性值 componentId 控制 --> <component :is"componentId"></component>具体可以官网文档中的 动态组件内置的组件compone…

ulli*3 实现翻书动画效果

按惯例&#xff0c;上GIF&#xff1a;重现&#xff1a;https://codepen.io/anon/pen/JJBxOm 这是我今天参加面试时候&#xff0c;面试官让我做的一道题&#xff0c;面试官坐我旁边看我现场做&#xff0c;然而我比较菜&#xff0c;回来后才做出来…… 来看看HTML部分&#xff1a…

cookie,session 会话跟踪技术

会话跟踪技术 1 什么是会话跟踪技术 我们需要先了解一下什么是会话&#xff01;可以把会话理解为客户端与服务器之间的一次会晤&#xff0c;在一次会晤中可能会包含多次请求和响应。例如你给10086打个电话&#xff0c;你就是客户端&#xff0c;而10086服务人员就是服务器了。…

200行代码写一个简易的dva

在美团实习的时候&#xff0c;第一次接触到dva这样的react框架&#xff0c;回学校的时候&#xff0c;就想有机会自己实现一下这样的框架&#xff0c;虽然自己水平有限&#xff0c;但是可以试一试哈。 目标是实现dva model的同步和异步 dispatch action。 看看 dva 的构成 let…

linux 切换root_Linux运维服务篇:流量监控工具iftop部署及详细参数分享

Linux流量监控工具--iftop介绍&#xff1a;在类Unix系统中可以使用top查看系统资源、进程、内存占用等信息。查看网络状态可以使用netstat、nmap等工具。若要查看实时的网络流量&#xff0c;监控TCP/IP连接等&#xff0c;则可以使用iftop。一、iftop是什么&#xff1f;iftop是类…

RabbitMQ安装以及集群部署

本次记录安装RabbitMQ的过程&#xff0c;只针对MAC下单机版安装、单机集群安装方法以及配置haproxy负载均衡。 RabbitMQ单机版本安装RabbitMQ单机集群安装方法&#xff08;适合开发练习&#xff09;RabbitMQ配置haproxy负载均衡RabbitMQ集群测试&#xff08;待续&#xff09;参…

r 保留之前曲线_生存曲线居然能够批量绘制了

生信分析第三步&#xff1a;生存曲线批量绘制各位解螺旋的小伙伴大家好&#xff0c;我是先锋宇&#xff0c;欢迎大家来到每周日的先锋宇专栏&#xff0c;经过前两期推文的学习&#xff0c;很多小伙伴都私信我说从先锋宇助教的专栏很接地气&#xff0c;自己能够开始慢慢处理数据…

基于vue自动化表单实践

背景 B端系统表单较多&#xff0c;且表单可能含有较多字段字段较多的表单带来了大片HTML代码在大片HTML中&#xff0c;混杂着参数绑定、事件处理等逻辑&#xff0c;不利于维护技术栈 Vue&#xff0c;Element(默认表单布局)适合中后台项目快速开发 目标 通过json配置快速生成表单…

天津科技大学计算机学院复试分数线,2021天津科技大学研究生复试分数线

2021天津科技大学研究生复试分数线已经公布&#xff0c;包含学术学位、专业学位、专项计划复试分数线&#xff0c;供大家参考&#xff0c;如意了在此祝广大考研学子都能顺利上岸。一、2021年天津科技大学研究生分数线1&#xff0e;专业分数线各学院严格执行《2021年全国硕士研究…

使用Eclipse Hibernate插件逐步为POJO域Java类和hbm自动生成代码

概述&#xff1a; 在本教程中&#xff0c;我们将使用Eclipse Hibernate工具自动生成域对象和相应的hbm xml文件。 如果您正在处理大型或中型项目&#xff0c;并且开始时有超过5个以上的表&#xff0c;则可能会发现此插件是自动生成映射域对象java文件和相应* .hbm.xml的绝佳工具…