本篇仍以问题为驱动

一、什么时Service?

Service是Android程序中四大基础组件之一,它和Activity一样都是Context的子类,只不过它没有UI界面,是在后台运行的组件。Service是Android中实现程序后台运行的解决方案,它非常适用于去执行那些不需要和用户交互而且还要求长期运行的任务。Service默认并不会运行在子线程中,它也不运行在一个独立的进程中,它同样执行在UI线程中,因此,不要在Service中执行耗时的操作,除非你在Service中创建了子线程来完成耗时操作。

二、Service种类

按运行地点分类:

按运行类型分类:

按使用方式分类:

三、Service生命周期

OnCreate()
系统在service第一次创建时执行此方法,来执行只运行一次的初始化工作。如果service已经运行,这个方法不会被调用。

onStartCommand()
每次客户端调用startService()方法启动该Service都会回调该方法(多次调用)。一旦这个方法执行,service就启动并且在后台长期运行。通过调用stopSelf()或stopService()来停止服务。

OnBind()
当组件调用bindService()想要绑定到service时(比如想要执行进程间通讯)系统调用此方法(一次调用,一旦绑定后,下次再调用bindService()不会回调该方法)。在你的实现中,你必须提供一个返回一个IBinder来以使客户端能够使用它与service通讯,你必须总是实现这个方法,但是如果你不允许绑定,那么你应返回null。

OnUnbind()
当前组件调用unbindService(),想要解除与service的绑定时系统调用此方法(一次调用,一旦解除绑定后,下次再调用unbindService()会抛出异常)。

OnDestory()
系统在service不再被使用并要销毁时调用此方法(一次调用)。service应在此方法中释放资源,比如线程,已注册的侦听器,接收器等等.这是service收到的最后一个调用。

下面介绍三种不同情况下Service的生命周期情况。

1.startService / stopService

生命周期顺序:onCreate->onStartCommand->onDestroy

如果一个Service被某个Activity 调用 Context.startService方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务,还有一种方法可以关闭服务,在设置中,通过应用->找到自己应用->停止。

注意点:

①第一次 startService 会触发 onCreate 和 onStartCommand,以后在服务运行过程中,每次 startService 都只会触发 onStartCommand

②不论 startService 多少次,stopService 一次就会停止服务

2.bindService / unbindService

生命周期顺序:onCreate->onBind->onUnBind->onDestroy

如果一个Service在某个Activity中被调用bindService方法启动,不论bindService被调用几次,Service的onCreate方法只会执行一次,同时onStartCommand方法始终不会调用。

当建立连接后,Service会一直运行,除非调用unbindService来接触绑定、断开连接或调用该Service的Context不存在了(如Activity被Finish——即通过bindService启动的Service的生命周期依附于启动它的Context),系统在这时会自动停止该Service。

注意点:

第一次 bindService 会触发 onCreate 和 onBind,以后在服务运行过程中,每次 bindService 都不会触发任何回调

3.混合型(上面两种方式的交互)

当一个Service在被启动(startService)的同时又被绑定(bindService),该Service将会一直在后台运行,并且不管调用几次,onCreate方法始终只会调用一次,onStartCommand的调用次数与startService调用的次数一致(使用bindService方法不会调用onStartCommand)。同时,调用unBindService将不会停止Service,必须调用stopService或Service自身的stopSelf来停止服务。

在什么情况下使用 startService 或 bindService 或 同时使用startService 和 bindService?

①如果你只是想要启动一个后台服务长期进行某项任务那么使用 startService 便可以了。

②如果你想要与正在运行的 Service 取得联系,那么有两种方法,一种是使用 broadcast ,另外是使用 bindService ,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且 BroadcastReceiver 本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择使用 bindService(这个时候你便同时在使用 startService 和 bindService 了,这在 Activity 中更新 Service 的某些运行状态是相当有用的)。

③如果你的服务只是公开一个远程接口,供连接上的客服端(android 的 Service 是C/S架构)远程调用执行方法。这个时候你可以不让服务一开始就运行,而只用 bindService ,这样在第一次 bindService 的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是Remote Service,那么该效果会越明显(当然在 Service 创建的时候会花去一定时间,你应当注意到这点)。

四、Service与Activity怎么实现通信

1.Binder:

  • 多个客户端可以全部连接到该服务。但是,系统只会在第一个客户端绑定时调用您的服务的onBind()方法来检索IBinder。系统然后将相同的IBinder传递给绑定的任何其他客户端,而无需再次调用onBind()。
  • 当最后一个客户端解除绑定服务时,系统会销毁该服务(除非该服务也由startService()启动)。
  • 实现绑定服务时,最重要的部分是定义onBind()回调方法返回的接口。您可以通过几种不同的方法来定义服务的IBinder接口,以下部分将讨论每种技术。

(1)扩展Binder类

简述:如果您的Service对您自己的应用程序是私有的,并且与客户端在相同的进程中运行(这是常见的),则应该通过扩展Binder类并创建其实例,onBind()返回该实例。 客户端收到Binder,可以使用它直接访问Binder实现或甚至Service中可用的公共方法。

实现如下:

通过 Binder 接口的形式实现,当 Activity 绑定 Service 成功的时候 Activity 会在 ServiceConnection 的类 的 onServiceConnected()回调方法中获取到 Service 的 onBind()方法 return 过来的 Binder 的子类,然后通过对象调用方法。

  这里以音乐播放service为例
  1. 新建一个继承自Service的类MusicService,然后在AndroidManifest.xml里注册这个Service
  2. Activity里面使用bindService方式启动MyService,也就是绑定了MyService
    (到这里实现了绑定,Activity与Service通信的话继续下面的步骤)
  3. 新建一个继承自Binder的类MusicBinder(一般为service内部类)
  4. 在MusicService里实例化一个MusicBinder对象mBinder,并在onBind回调方法里面返回这个mBinder对象
  5. 第2步bindService方法需要一个ServiceConnection类型的参数,在ServiceConnection里可以取到一个IBinder对象,就是第4步onBinder返回的mBinder对象(也就是在Activity里面拿到了Service里面的mBinder对象)
  6. 在Activity里面拿到mBinder之后就可以调用这个binder里面的方法了(也就是可以给Service发消息了),需要什么方法在MyBinder类里面定义实现就行了。如果需要Service给Activity发消息的话,通过这个binder注册一个自定义回调即可。
public class MusicService extends Service {
//实现一个播放音乐的servicepublic MediaPlayer mediaPlayer;private MusicBinder mBinder = new MusicBinder(this); public MusicService() {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource("/storage/emulated/0/netease/cloudmusic/Music/雷军 - Are You OK.MP3");
mediaPlayer.prepare();
mediaPlayer.setLooping(true);
} catch (Exception e) { }
} @Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
} @Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);
} public void playOrPause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
} else {
mediaPlayer.start();
}
} public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(Environment.getExternalStorageState()
+ "/storage/emulated/0/netease/cloudmusic/Music/雷军 - Are You OK.MP3");
mediaPlayer.prepare();
mediaPlayer.seekTo(0);
} catch (Exception e) {
}
}
} public class MusicBinder extends Binder {
MusicService musicService;
private OnTestListener mListener; public MusicBinder(MusicService service) {
this.musicService = service;
} public MusicService getService() {
return musicService;
} public void playOrPause() {
musicService.playOrPause();
mListener.onTest(musicService.mediaPlayer.isPlaying() ? "play" : "pause");
} public void stop() {
musicService.stop();
mListener.onTest("stop");
} // MyBinder 里面提供一个注册回调的方法
public void setOnTestListener(OnTestListener listener) {
this.mListener = listener;
} } //自定义一个回调接口
public interface OnTestListener {
void onTest(String str);
}
}

activity代码如下:

public class MusicActivity extends Activity implements MusicService.OnTestListener {

    private MusicService.MusicBinder mBinder;
private MusicService mService;
private ServiceConnection sc = new MusicServiceConnection();
private TextView textView; @Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_btns);
init();
} private void init() {
textView = (TextView) findViewById(R.id.tv_music);
findViewById(R.id.btn_1).setOnClickListener(v -> {
//绑定Service
Intent intent = new Intent(this, MusicService.class);
startService(intent);
bindService(intent, sc, Context.BIND_AUTO_CREATE); }); findViewById(R.id.btn_2).setOnClickListener(v -> {
//解除绑定
unbindService(sc);
});
findViewById(R.id.btn_3).setOnClickListener(v -> {
//也可以直接通过binder获取的service实例,操作播放暂停方法
// mService.playOrPause();
//通过binder实例操作binder内部的service方法
mBinder.playOrPause();
});
findViewById(R.id.btn_4).setOnClickListener(v -> {
// mService.stop();
mBinder.stop();
});
} @Override
public void onTest(String str) {
//接口回调,提供给service向activity的通信,实现双向通信
textView.setText(str);
} class MusicServiceConnection implements ServiceConnection { @Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mBinder = (MusicService.MusicBinder) iBinder;
mService = mBinder.getService();
mBinder.setOnTestListener(MusicActivity.this);
} @Override
public void onServiceDisconnected(ComponentName componentName) {
mService = null;
}
}
}
 
(2)使用Messenger:(进程间通信)

简述:如果需要Service 和客户端位于不同的进程,则可以使用Messenger为服务创建一个interface。 以这种方式,服务定义响应不同类型的Message对象的Handler。 该Handler是Messenger的基础,可以与客户端共享IBinder,允许客户端使用Message对象向服务发送命令。 此外,客户端可以定义自己的Messenger,因此服务可以发回消息。

这是执行进程间通信(IPC)的最简单的方法,因为Messenger将所有请求排队到单个线程中,以便使用者不必将服务设计为线程安全。

它引用了一个Handler对象,以便others能够向它发送消息(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message的通信(即两个进程间可以通过Message进行通信),在服务端使用Handler创建一个Messenger,客户端持有这个Messenger就可以与服务端通信了。一个Messeger不能同时双向发送,两个就就能双向发送了

 
直接在onServiceConnected回调中像本地服务一样转换会报强转错误

使用:如果您需要服务与远程进程通信,那么可以使用Messenger为服务提供接口。这种技术允许执行进程间通信(IPC),而无需使用AIDL。

以下是Messenger使用如下:

A、Service实现一个Handler,接收客户端发送的消息。

B、Handler用于创建一个Messenger对象(这是对Handler的引用)。

C、Messenger创建一个IBinder,Service将IBinder 从onBind()返回给客户端。

D、客户端使用IBinder来实例化Messenger (引用服务的Handler),客户端利用Messenger将Message对象发送到服务。

E、Service接收 Message在其Handler的handleMessage()方法中进行处理。

service实现代码

a. service创建Handler对象。

  * 处理来自客户端的消息
*/
private Handler mHandler = new Handler() {
//创建Handler对象
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello,remote service", Toast.LENGTH_SHORT).show();
//通过message对象获取客户端传递过来的Messenger对象。
Messenger messenger = msg.replyTo;
if (messenger != null) {
Message messg = Message.obtain(null, MSG_SAY_HELLO);
try {
//向客户端发送消息
messenger.send(messg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
case MSG_MUSIC_PLAY:
//播放/暂停音乐
playOrPause();
break;
case MSG_MUSIC_STOP:
//停止播放
stop();
break;
default:
break;
}
}
};

b.创建Messenger对象

    //创建Mesenger 对象
public Messenger mMessenger;
public RemoteMusicService() {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource("/storage/emulated/0/netease/cloudmusic/Music/雷军 - Are You OK.MP3");
mediaPlayer.prepare();
mediaPlayer.setLooping(true);
} catch (Exception e) { }
mMessenger = new Messenger(mHandler);
}

c.onBind()返回IBinder对象


private MusicBinder mBinder = new MusicBinder(this);
 @Nullable
@Override
public IBinder onBind(Intent intent) {
//通过Mesenger对象获取IBinder实例,并返回
return mMessenger.getBinder();
}

d.服务端接收客户端发送的消息,并在Handler对象的hanleMessage方法中进行处理。

完整service代码如下

public class RemoteMusicService extends Service {
//实现一个播放音乐的service
public static final int MSG_SAY_HELLO = 101;
public static final int MSG_MUSIC_PLAY = 102;
public static final int MSG_MUSIC_STOP = 103;
public MediaPlayer mediaPlayer;
/**
* 处理来自客户端的消息
*/
private Handler mHandler = new Handler() {
//创建Handler对象
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello,remote service", Toast.LENGTH_SHORT).show();
//通过message对象获取客户端传递过来的Messenger对象。
Messenger messenger = msg.replyTo;
if (messenger != null) {
Message messg = Message.obtain(null, MSG_SAY_HELLO);
try {
//向客户端发送消息
messenger.send(messg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
case MSG_MUSIC_PLAY:
//播放/暂停音乐
playOrPause();
break;
case MSG_MUSIC_STOP:
//停止播放
stop();
break;
default:
break;
}
}
};
//创建Mesenger 对象
public Messenger mMessenger;
private MusicBinder mBinder = new MusicBinder(this); public RemoteMusicService() {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource("/storage/emulated/0/netease/cloudmusic/Music/雷军 - Are You OK.MP3");
mediaPlayer.prepare();
mediaPlayer.setLooping(true);
} catch (Exception e) { }
mMessenger = new Messenger(mHandler);
} @Nullable
@Override
public IBinder onBind(Intent intent) {
//通过Mesenger对象获取IBinder实例,并返回
return mMessenger.getBinder();
} @Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
} public void playOrPause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
} else {
mediaPlayer.start();
}
} public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(Environment.getExternalStorageState() + "/storage/emulated/0/netease/cloudmusic/Music/雷军 - Are You OK.MP3");
mediaPlayer.prepare();
mediaPlayer.seekTo(0);
} catch (Exception e) {
}
}
} public class MusicBinder extends Binder {
RemoteMusicService musicService; public MusicBinder(RemoteMusicService service) {
this.musicService = service;
} public void playOrPause() {
musicService.playOrPause();
} public void stop() {
musicService.stop();
} }
}

AndroidManifest文件

 <service
android:name=".service.musicService.RemoteMusicService"
android:enabled="true"
android:exported="true"
android:icon="@drawable/ic_menu_camera"
android:label="music"
android:process=":music" />

exported要设置为true,否则别的进程不能使用该Service

客户端activity实现

a.绑定Service

b. 连接成功回调

实现ServiceConnection,必须覆盖两个回调方法:

findViewById(R.id.btn_5).setOnClickListener(v -> {
Intent intent = new Intent(this, RemoteMusicService.class);
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// 当与服务端连接成功时,回调该方法。
//通过IBinder参数获取Messenger
mRemoteMessenger = new Messenger(iBinder);
textView.setText("connected");
} @Override
public void onServiceDisconnected(ComponentName componentName) {
mRemoteMessenger = null;
textView.setText("disconnected");
}
}, Context.BIND_AUTO_CREATE);
textView.setText("connecting");
});

c. 向服务端发送消息 
Message属性replyTo不是必须的,如果希望Service向客户端发送消息则需要。

private void sendMsg(int what) {
if (mRemoteMessenger == null) return; //创建消息,设置what属性
Message msg = Message.obtain(null, what); //replyTo不是必须的,如果希望Service向客户端发送消息则需要设置。
msg.replyTo = mMessenger;
try { //发送消息
mRemoteMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}

d. 接收Service的回复

 private Messenger mRemoteMessenger;
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
textView.setText("hello");
break;
default:
break;
}
}
};
private Messenger mMessenger = new Messenger(mHandler);

e. 解除绑定

需要断开与服务的连接时,请调用unbindService()。

完整客户端activity代码如下

public class MusicActivity extends Activity {
private TextView textView;
private Messenger mRemoteMessenger;
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
textView.setText("hello");
break;
default:
break;
}
}
};
private Messenger mMessenger = new Messenger(mHandler); @Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_btns);
init();
} private void init() {
textView = (TextView) findViewById(R.id.tv_music);
findViewById(R.id.btn_5).setOnClickListener(v -> {
Intent intent = new Intent(this, RemoteMusicService.class);
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// 当与服务端连接成功时,回调该方法。
//通过IBinder参数获取Messenger
mRemoteMessenger = new Messenger(iBinder);
textView.setText("connected");
} @Override
public void onServiceDisconnected(ComponentName componentName) {
mRemoteMessenger = null;
textView.setText("disconnected");
}
}, Context.BIND_AUTO_CREATE);
textView.setText("connecting");
});
findViewById(R.id.btn_6).setOnClickListener(v -> {
sendMsg(MSG_SAY_HELLO);
});
findViewById(R.id.btn_7).setOnClickListener(v -> {
sendMsg(MSG_MUSIC_PLAY);
});
findViewById(R.id.btn_8).setOnClickListener(v -> {
sendMsg(MSG_MUSIC_STOP);
});
} private void sendMsg(int what) {
if (mRemoteMessenger == null) return; //创建消息,设置what属性
Message msg = Message.obtain(null, what); //replyTo不是必须的,如果希望Service向客户端发送消息则需要设置。
msg.replyTo = mMessenger;
try { //发送消息
mRemoteMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
} }
(3)使用AIDL:

简述:AIDL(Android Interface Definition Language)执行所有的工作,将对象分解为基元,操作系统可以在进程之间了解和编组它们以执行IPC。 之前使用的Messenger技术实际上是基于AIDL作为其底层结构。 如上所述,Messenger在单个线程中创建所有客户端请求的队列,因此服务一次接收一个请求。 但是,如果您希望您的服务同时处理多个请求,则可以直接使用AIDL。 在这种情况下,您的服务必须能够进行多线程并建立线程安全。

要直接使用AIDL,您必须创建一个定义编程接口的.aidl文件。 Android SDK工具使用此文件生成一个实现接口并处理IPC的抽象类,然后您可以在服务中扩展它。

注意:大多数应用程序不应该使用AIDL创建绑定的服务,因为它可能需要多线程功能,并可能导致更复杂的实现。因此,AIDL不适用于大多数应用程序。

aidl 比较适合当客户端和服务端不在同一个应用下的场景。

(4)通过广播进行交互

(5)使用rxBus(轻量级通信,缺点,发生错误难以debug)

五、IntentService有什么优点(与Service区别)

IntentService是Service的子类,是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题

  • 会创建独立的worker线程来处理所有的Intent请求;
  • 会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
  • 所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
  • 为Service的onBind()提供默认实现,返回null;
  • 为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;
  • IntentService不会阻塞UI线程,而普通Serveice会导致ANR异常
  • Intentservice若未执行完成上一次的任务,将不会新开一个线程,是等待之前的任务完成后,再执行新的任务,等任务完成后再次调用stopSelf()

简单实现

service相关的更多相关文章

  1. 与Java Web Service相关的若干概念(JAX-WS,JAX-RS)

    WS ,JAX-WS ,JAX-RS,REST,Restlet,SOAP l  JWS: 是指与webservice相关的J2EE(其实现在应该叫做Java EE吧)技术叫做 JWS(全称就是 jav ...

  2. Service相关--读书笔记

    2013-12-30 18:16:11 1. Service和Activty都是从Context里面派生出来的,因此都可以直接调用getResource(),getContentResolver()等 ...

  3. 关于service相关知识的认识

    做android的程序开发也有了许久了,当做一个大程序的时候,越来越发现service是非常有用的方法,当你想后台运行数据或者音乐播放操作的时候,都可以才有service,根据实际情况,写成local ...

  4. kubernetes 学习 service相关

    1:         service有什么用? 直接通过Pod的IP地址和端口号可以访问容器应用,但是pod的IP地址是不可靠的,比如POD出现故障后,有可能在另外一个NOde上启动,这样Pod的IP ...

  5. WCF RIA SERVICE相关技术

    WCF RIA SERVICE实体属性拷贝 private void DoSubmit() { ((IEditableObject)this.RepairContract).EndEdit(); va ...

  6. Linux的Service/Daemon你真的懂了吗?

    一 service与一般的程序的区别 service(也称为daemon)表示后台运行的程序,一般随系统的启动自动地启动且在用户logoff后仍然能够继续运行.该daemon进程一般在启动后需要与父进 ...

  7. Android Service完全解析,关于服务你所需知道的一切(下)

    转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要 ...

  8. 【转】基于CXF Java 搭建Web Service (Restful Web Service与基于SOAP的Web Service混合方案)

    转载:http://www.cnblogs.com/windwithlife/archive/2013/03/03/2942157.html 一,选择一个合适的,Web开发环境: 我选择的是Eclip ...

  9. 利用Meida Service的Java SDK来调用Azure Media Services的Index V2实现视频字幕自动识别

    Azure Media Services新的Index V2 支持自动将视频文件中的语音自动识别成字幕文件WebVtt,非常方便的就可以跟Azure Media Player集成,将一个原来没字幕的视 ...

随机推荐

  1. Python configparser 读取指定节点内容失败

    # !/user/bin/python # -*- coding: utf-8 -*- import configparser # 生成一个config文件 config = configparser ...

  2. 第四天 Java语言基础

    一.函数的概念 1)什么函数 函数就是定义在类中的具有特定功能的一段独立小程序,并能被多次使用. 2)问题引入 在昨天讲述使用循环嵌套画出矩形.但有问题,每次要画矩形都要写很多重复性的代码,能不能将这 ...

  3. jdbc 增删改查以及遇见的 数据库报错Can't get hostname for your address如何解决

    最近开始复习以前学过的JDBC今天肝了一晚上 来睡睡回笼觉,长话短说 我们现在开始. 我们先写一个获取数据库连接的jdbc封装类 以后可以用 如果不是maven环境的话在src文件下新建一个db.pr ...

  4. appium---【已解决】【Mac】如何查看java的安装路径及JAVA_HOME环境变量的配置

    报错截图:根据提示可以看出,JAVA_HOME的环境变量配置错误,需要重新配置. 1.查看Java版本 打开mac电脑,查看java版本,打开终端Terminal,通过命令查看java的版本 Luck ...

  5. Java Native Interface调用C++代码

    概述 Java Native Interface译为Java原生接口,简称JNI.Java并不是完美的,它的不足体现在运行速度要比传统的C++慢上许多,并且无法直接访问到操作系统底层,为此Java提供 ...

  6. C#语言介绍

    C#(读作“See Sharp”)是一种简单易用的新式编程语言,不仅面向对象,还类型安全. C# 源于 C 语言系列,C.C++.Java 和 JavaScript 程序员很快就可以上手使用. C# ...

  7. HTML入门知识汇总

    1. HTML认识 1.1 什么是HTML HTML是描述(制作)网页的语言,指的是超文本标记语言(Hyper Text Markup Language). 超文本:就是指页面内可以包含图片.链接.甚 ...

  8. 联发科Helio P90,MT6779VWB芯片处理器

    联发科(p90)MT6779VWB芯片是一个集成了蓝牙.fm.wlan和gps模块的高度集成的基带平台,包括调制解调器和应用处理子系统.支持LTE/LTE-A和C2K智能手机应用程序.该芯片集成了两个 ...

  9. 多功能设备mfd驱动

    一.概述 mfd是Multifunction device的简称,即多功能设备,是许多有共性的设备的集合,mfd由核心层(core)以及其下的"子设备"组成.从下文将会看到,mfd ...

  10. 关于a[i]++和a[i++]说明

    1.a[i]++:表示对当前数组元素值自增,此时可以把a[i]简单看做一个变量x,操作后,x的值加1: int main() { ]; ; a[i] = ; a[i]++; printf(" ...