运行有问题或需要源码请点赞关注收藏后评论区留言~~~
一、服务的启动和停止
服务Service是Android的四大组件之一,它常用于页面的高级场合,这些系统服务平时几乎感觉不到它们的存在,却是系统不可或缺的重要组成部分。
既然Android自带了系统服务,App也可以拥有自己的服务,服务Service与活动Activity相比,不同之处在于没有对应的页面,相同之处在于都有生命周期 常用方法如下
1:onCreate 创建服务
2:onStart 开始服务
3:onStartCommand 开始服务
4:onDestroy 销毁服务
5:onBind 绑定服务
6:onUnbind 解除绑定
7:onRebind 重新绑定
点击启动服务和停止服务会调用相对应得方法 效果如下
代码如下
Java类
package com.example.chapter11; import android.annotation.SuppressLint; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import com.example.chapter11.service.NormalService; import com.example.chapter11.util.DateUtil; @SuppressLint("StaticFieldLeak") public class ServiceNormalActivity extends AppCompatActivity implements View.OnClickListener { private static TextView tv_normal; private Intent mIntent; // 声明一个意图对象 private static String mDesc; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_service_normal); tv_normal = findViewById(R.id.tv_normal); findViewById(R.id.btn_start).setOnClickListener(this); findViewById(R.id.btn_stop).setOnClickListener(this); mDesc = ""; // 创建一个通往普通服务的意图 mIntent = new Intent(this, NormalService.class); } @Override public void onClick(View v) { if (v.getId() == R.id.btn_start) { // 点击了启动服务按钮 startService(mIntent); // 启动指定意图的服务 } else if (v.getId() == R.id.btn_stop) { // 点击了停止服务按钮 stopService(mIntent); // 停止指定意图的服务 } } public static void showText(String desc) { if (tv_normal != null) { mDesc = String.format("%s%s %s\n", mDesc, DateUtil.getNowDateTime("HH:mm:ss"), desc); tv_normal.setText(mDesc); } } }
XML文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/btn_start" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="启动服务" android:textColor="@color/black" android:textSize="17sp" /> <Button android:id="@+id/btn_stop" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="停止服务" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout> <TextView android:id="@+id/tv_normal" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="5dp" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout>
二、服务的绑定与解绑
服务启停除了上一小节介绍的普通方式,也就是绑定服务和解绑服务。对于服务来说,便要求提供粘合剂Binder指定服务的绑定关系,同时黏合剂指定服务的绑定关系,同时黏合剂还负责在两个组件或者在两个进程之间交流通信。效果如下
延迟绑定与立即绑定的生命周期区别在于
1:延迟绑定的首次绑定操作只触发onBind方法,再次绑定操作只触发onRebind方法
2:延迟绑定的解绑操作只触发onUnbind方法
代码如下
Java类
package com.example.chapter11; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import com.example.chapter11.service.BindDelayService; import com.example.chapter11.util.DateUtil; public class BindDelayActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "BindDelayActivity"; private static TextView tv_delay; private Intent mIntent; // 声明一个意图对象 private static String mDesc; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bind_delay); tv_delay = findViewById(R.id.tv_delay); findViewById(R.id.btn_start).setOnClickListener(this); findViewById(R.id.btn_bind).setOnClickListener(this); findViewById(R.id.btn_unbind).setOnClickListener(this); findViewById(R.id.btn_stop).setOnClickListener(this); mDesc = ""; // 创建一个通往延迟绑定服务的意图 mIntent = new Intent(this, BindDelayService.class); } @Override public void onClick(View v) { if (v.getId() == R.id.btn_start) { // 点击了开始服务按钮 startService(mIntent); // 启动服务 } else if (v.getId() == R.id.btn_bind) { // 点击了绑定服务按钮 boolean bindFlag = bindService(mIntent, mFirstConn, Context.BIND_AUTO_CREATE); // 绑定服务 Log.d(TAG, "bindFlag=" + bindFlag); } else if (v.getId() == R.id.btn_unbind) { // 点击了解绑服务按钮 if (mBindService != null) { unbindService(mFirstConn); // 解绑服务 mBindService = null; } } else if (v.getId() == R.id.btn_stop) { // 点击了停止服务按钮 stopService(mIntent); // 停止服务 } } public static void showText(String desc) { if (tv_delay != null) { mDesc = String.format("%s%s %s\n", mDesc, DateUtil.getNowDateTime("HH:mm:ss"), desc); tv_delay.setText(mDesc); } } private BindDelayService mBindService; // 声明一个服务对象 private ServiceConnection mFirstConn = new ServiceConnection() { // 获取服务对象时的操作 public void onServiceConnected(ComponentName name, IBinder service) { // 如果服务运行于另外一个进程,则不能直接强制转换类型,否则会报错 mBindService = ((BindDelayService.LocalBinder) service).getService(); Log.d(TAG, "onServiceConnected"); } // 无法获取到服务对象时的操作 public void onServiceDisconnected(ComponentName name) { mBindService = null; Log.d(TAG, "onServiceDisconnected"); } }; }
XML文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/btn_start" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="启动服务" android:textColor="@color/black" android:textSize="15sp" /> <Button android:id="@+id/btn_bind" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="绑定服务" android:textColor="@color/black" android:textSize="15sp" /> <Button android:id="@+id/btn_unbind" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="解绑服务" android:textColor="@color/black" android:textSize="15sp" /> <Button android:id="@+id/btn_stop" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="停止服务" android:textColor="@color/black" android:textSize="15sp" /> </LinearLayout> <TextView android:id="@+id/tv_delay" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="5dp" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout>
三、推送服务到前台
服务没有自己的布局文件,意味着无法直接在页面上展示服务信息,要想了解服务的运行情况,要么通过打印日志观察,要么通过某个页面的静态控件显示运行结果,然而活动页面有自身的生命周期,为此Android设计了一个让服务在前台运行的机制,也就是在手机的通知栏展示服务的画像,同时允许自己是否需要在通知栏显示 包括下面两个方法
1:startForeground 把当前服务切换到前台运行 即展示到通知栏
2:stopForeground 停止前台运行 即取消通知栏上的展示
效果如下 连接了真机后会在 后台显示
代码如下
Java类
package com.example.chapter11; import android.content.Intent; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.example.chapter11.service.MusicService; import com.example.chapter11.util.ViewUtil; public class ForegroundServiceActivity extends AppCompatActivity implements View.OnClickListener { private EditText et_song; private Button btn_send_service; private boolean isPlaying = true; // 是否正在播放 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_foreground_service); et_song = findViewById(R.id.et_song); btn_send_service = findViewById(R.id.btn_send_service); btn_send_service.setOnClickListener(this); } @Override public void onClick(View v) { if (v.getId() == R.id.btn_send_service) { if (TextUtils.isEmpty(et_song.getText())) { Toast.makeText(this, "请填写歌曲名称", Toast.LENGTH_SHORT).show(); return; } // 创建一个通往音乐服务的意图 Intent intent = new Intent(this, MusicService.class); intent.putExtra("is_play", isPlaying); // 是否正在播放音乐 intent.putExtra("song", et_song.getText().toString()); btn_send_service.setText(isPlaying?"暂停播放音乐":"开始播放音乐"); startService(intent); // 启动音乐播放服务 isPlaying = !isPlaying; } } }
XML文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp" > <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:text="歌曲名称:" android:textColor="@color/black" android:textSize="17sp" /> <EditText android:id="@+id/et_song" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_margin="5dp" android:background="@drawable/editext_selector" android:hint="请填写歌曲名称" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout> <Button android:id="@+id/btn_send_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="开始播放音乐" android:textColor="#000000" android:textSize="17sp" /> </LinearLayout>
创作不易 觉得有帮助请点赞关注收藏~~~