Intent Service
默认情况下,服务在与启动它们的组件相同的主线程中运行。因此,需要由服务执行的任何CPU密集型任务都应该在新线程中进行,从而避免影响调用应用程序的性能。
JobIntentService 类是一个方便类(继承自 Service 类),它设置一个工作线程来处理后台任务,并以异步方式处理每个请求。一旦服务处理了所有排队的请求,它就会退出。使用 JobIntentService 类时所需要的只是实现onHandleWork() 方法,其中包含要为每个请求执行的代码。
对于不需要同步处理请求的服务,推荐选择JobIntentService。然而,需要同步处理请求的服务需要从Service类中子类化,并手动实现和管理线程以有效地处理任何CPU密集型任务。
Bound Service
绑定服务允许启动组件与服务交互并从服务接收结果。通过进程间通信(IPC)的实现,这种交互也可以跨进程边界进行。例如,活动可以启动一个服务来处理音频回放。
同样,该服务很可能需要向呼叫活动传递信息,以指示当前音轨已经完成,并提供即将开始播放的下一个音轨的详细信息
组件(在此上下文中也称为客户端)通过调用 bindService() 方法启动并绑定到绑定服务。此外,多个组件可能会同时绑定到一项服务。当客户端不再需要服务绑定时,应该调用 unbindService() 方法。当最后一个绑定客户端与服务解除绑定时,该服务将被Android运行时系统终止。
绑定服务也可以通过调用 startService() 启动。一旦启动,组件可能会通过 bindService() 调用绑定到它。当绑定服务通过调用 startService() 启动时,即使在最后一个客户端从它中解绑后,它也会继续运行。
绑定服务必须包含 onBind() 方法的实现,该方法在最初创建服务时和其他客户端随后绑定到正在运行的服务时调用。此方法的目的是将 IBinder 类型的对象返回给绑定客户端,其中包含客户端与服务通信所需的信息。
在实现客户端和绑定服务之间的通信方面,推荐的技术取决于客户端和服务是位于同一流程中还是不同的流程中,以及服务对客户端是否是私人的。可以通过扩展Binder类并从 onBind() 方法返回实例来实现本地通信。另一方面,进程间通信需要实现信使和处理程序。
服务必须创建为Android服务类(更具体地说android.app.Service)或其子类(如android.app.IntentService)的子类。作为子类程序的一部分,必须覆盖以下一个或多个超类回调方法,这取决于正在创建的服务的确切性质:
onStartCommand():这个方法当服务被另一个组件调用 startService()方法开启服务时调用,这个方法不需要为绑定服务实现
onBind():当一个组件绑定一个服务去调用 bindService() 方法时调用这个方法,当实现绑定服务,这个方法必须返回一个 IBinder 对象去方便和客户端的通信
onCreate():这个方法的作用是,执行初始化任务的位置。这个方法在,onStartCommand() 或者第一次调用 onBind() 方法之前被调用
onDestroy():服务将要被销毁时被调用
onHandleWork():仅适用于JobIntentService子类。调用此方法来处理服务的处理。它在与主应用程序分开的线程中执行。
控制销毁服务重启选项
onStartCommand() 回调方法需要返回一个整型值,以定义如果服务被Android运行时系统销毁,该服务应该会发生什么。
这些整型值的含义:
START_NOT_STICKY:当服务被销毁时,除非存在待传递的待定 Intent,否则系统不应重启该服务。
START_STICKY:表示,如果销毁操作出现在onStartCommand()方法返回之后,服务应该立即在销毁之后重启。在事件中没有待传递的 Intent onStartCommand() 回调方法伴随一个 NULL Intent 被调用。当服务被销毁时,正在处理的 Intent 会被丢弃。
START_REDELIVER_INTENT:表示,如果服务在从 onStartCommand() 回调方法返回后被销毁,则应重新启动服务,将当前意图重新交付到onStartCommand() 方法,然后是任何待定的 Intent。
Intent
intents(android. content.Intent)是一个 activity 可以启动另一个 activity 的消息传递系统。例如,一个 activity 可以发出一个 intent,请求启动包含在同一应用程序中的另一个 activity。然而,intent 也超越了这个概念,允许一个 activity 请求设备上任何其他适当注册的 activity 的服务,并为其配置了权限。
显式的 Intent 通过引用目标 activity 的组件名称(实际上是类名称)来请求启动特定 activity。当启动与发送 activity 在同一应用程序中的 activity 时,这种方法最常见。
这种方式启动另一个 Activity 可以进行传值
Intent i = new Intent(this, ActivityB.class);
i.putExtra("myString", "This is a message for ActivityB");
i.putExtra("myInt", 100);
startActivity(i);
另一种接收 activity 回传数据的方式
接收方
package com.example.basepractice.baseUI.dmo1;
import static android.app.Activity.RESULT_OK;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.navigation.Navigation;
import com.example.basepractice.R;
import com.example.basepractice.baseUI.demo2.Demo2Activity;
import com.example.basepractice.baseUI.demo3.Demo3Activity;
/**
* A simple {@link Fragment} subclass.
* Use the {@link NavHostFragment#newInstance} factory method to
* create an instance of this fragment. */public class NavHostFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private Button navButton;
private Button tabButton;
private Button listButton;
private Context navContext;
public NavHostFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment NavHostFragment.
*/ // TODO: Rename and change types and number of parameters
public static NavHostFragment newInstance(String param1, String param2) {
NavHostFragment fragment = new NavHostFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
/**
* 在 Fragment 的生命周期里,onAttach 方法会在 Fragment 与 Activity 关联时被调用,
* 此时可以获取到 Activity 的 Context。
* @param context
*/
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
navContext = context;
}
ActivityResultLauncher<Intent> getBackResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == RESULT_OK) {
Intent data = result.getData();
String str = data.getStringExtra("backData");
Log.i("TAG", "activity2的数据: " + str);
}
}
});
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 加载片段布局
View rootView = inflater.inflate(R.layout.fragment_nav_host, container, false);
navButton = rootView.findViewById(R.id.nav_btn);
navButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.findNavController(rootView).navigate(R.id.secondFragment);
}
});
tabButton = rootView.findViewById(R.id.go_tab_btn);
tabButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// startActivity(new Intent(navContext, Demo2Activity.class));
getBackResult.launch(new Intent(navContext, Demo2Activity.class));
}
});
listButton = rootView.findViewById(R.id.go_list_btn);
listButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(navContext, Demo3Activity.class));
}
});
// Inflate the layout for this fragment
return rootView;
}
}
发送方
package com.example.basepractice.baseUI.demo2;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Button;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.viewpager2.widget.ViewPager2;
import com.example.basepractice.R;
import com.example.basepractice.baseUI.basic.BasicActivity;
import com.example.basepractice.baseUI.demo2.adapter.TabPageAdapter;
import com.example.basepractice.baseUI.demo2.tab.Tab1Fragment;
import com.example.basepractice.baseUI.demo2.tab.Tab2Fragment;
import com.example.basepractice.baseUI.demo2.tab.Tab3Fragment;
import com.example.basepractice.baseUI.demo2.tab.Tab4Fragment;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
public class Demo2Activity extends BasicActivity implements Tab1Fragment.OnFragmentInteractionListener,
Tab2Fragment.OnFragmentInteractionListener, Tab3Fragment.OnFragmentInteractionListener,
Tab4Fragment.OnFragmentInteractionListener {
private TabLayout tabLayout;
private ViewPager2 viewPager2;
private Button backBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_demo2);
setupUI();
configureTabLayout();
}
private void setupUI() {
tabLayout = findViewById(R.id.tab_layout);
viewPager2 = findViewById(R.id.view_pager2);
backBtn = findViewById(R.id.back);
backBtn.setOnClickListener(v -> {
Intent intent = new Intent();
intent.putExtra("backData", "返回的数据");
setResult(RESULT_OK, intent);
finish();
});
}
protected void configureTabLayout() {
// 1、通过 addTab 方法添加Tab,for循环添加4个 Tab for (int i = 0; i < 4; i++) {
tabLayout.addTab(tabLayout.newTab());
}
// 2、创建 adapter 并设置 Tab 个数
TabPageAdapter adapter = new TabPageAdapter(this, tabLayout.getTabCount());
// 3、viewPager2 设置 adapter viewPager2.setAdapter(adapter);
// 4、创建 TabLayoutMediator 将 TabLayout 和 ViewPager2 关联
new TabLayoutMediator(tabLayout, viewPager2, (tab, position) -> {
tab.setText("Tab " + (position + 1));
}).attach();
}
@Override
public void onFragmentInteraction(Uri uri) {
}
}
运行效果
隐式 Intent 跳转浏览器
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.baidu.com"));
startActivity(intent);
广播 Intent 和广播接收者
Broadcast intents 是 Intent 对象,通过调用 Activity 类的 sendBroadcast()、sendStickyBroadcast() 或 sendOrderedBroadcast()方法(后者在需要广播结果时使用)进行广播。
创建广播 Intent 时,除了可选数据和类别字符串外,它还必须包括一个操作字符串。与标准 Intent 一样,数据使用键值对与 Intent 对象的 putExtra() 方法相结合,将数据添加到广播 Intent 中。可选类别字符串可以通过调用 addCategory() 方法分配给广播 Intent。
标识广播事件的操作字符串必须是唯一的,并且通常使用应用程序的软件包名称语法。例如,以下代码片段创建并发送广播 Intent,包括唯一的操作字符串和数据
应用程序通过注册广播接收器来监听特定的广播 Intent。广播接收器是通过扩展Android BroadcastReceiver类并覆盖 onReceive() 方法来实现的。然后,广播接收器可以在代码中或清单文件中注册。注册实施的一部分涉及创建 Intent 过滤器,以指示接收者需要监听的特定广播 Intent。这是通过引用广播 Intent 的动作字符串来实现的。当检测到匹配的广播时,会调用广播接收器的 onReceive() 方法,此时该方法在返回前有5秒的时间来执行任何必要的任务。需要注意的是,广播接收器不需要一直运行。如果检测到匹配的意图,Android运行时系统将在调用 onReceive() 方法之前自动启动广播接收器。
自定义接收者类
package com.example.basepractice.base.broadcastdemo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
public class DemoReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String message = String.valueOf(intent.getIntExtra("demoData", 9));
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
Log.i("braodTag", "onReceive: "+message);
}
}
注册接收者
package com.example.basepractice.baseUI.dmo1;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
import com.example.basepractice.base.broadcastdemo.DemoReceiver;
import com.example.basepractice.baseUI.basic.BasicActivity;
import com.example.basepractice.baseUI.dmo1.viewModel.DataViewModel;
import com.example.basepractice.R;
import com.example.basepractice.databinding.ActivityMainBinding;
public class MainActivity extends BasicActivity {
private BroadcastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setBroadcastReceiver();
}
private void setBroadcastReceiver() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.demo.broadcast");
receiver = new DemoReceiver();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S) {
// Android 12-13 使用 RECEIVER_NOT_EXPORTED(需检查 Context 兼容性)
registerReceiver(receiver, intentFilter, context.RECEIVER_NOT_EXPORTED);
} else {
Log.i("TAG", "setBroadcastReceiver: 版本低");
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
}
发送方
package com.example.basepractice.base.broadcastdemo;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.example.basepractice.R;
import com.example.basepractice.baseUI.basic.BasicActivity;
public class BroadcastDemoActivity extends BasicActivity {
private Button backButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_broadcast_demo);
setupUI();
}
private void setupUI() {
backButton = findViewById(R.id.back);
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
backAction();
}
});
}
private void backAction() {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setAction("com.demo.broadcast");
intent.putExtra("demoData",10000);
context.sendBroadcast(intent);
}
}
运行效果
绑定本地服务
bound服务是作为Android服务类的子类创建的,并且至少必须实现 onBind() 方法。客户端组件通过调用 bindService() 方法绑定到服务。对绑定服务的第一个绑定请求将导致对该服务的 onBind() 方法的调用(随后的绑定请求不会触发 onBind() 调用)。希望绑定到服务的客户端还必须实现一个ServiceConnection子类,其中包含onServiceConnected() 和onServiceDisconnected() 方法,一旦客户端-服务器连接建立或断开连接,这些方法将分别调用。在onServiceConnected() 方法的情况下,这将传递一个IBinder对象,其中包含客户端与服务交互所需的信息。
在客户端组件和绑定服务之间实现交互有两种建议的机制。如果绑定服务是本地和私有的,与客户端组件相同的应用程序(换句话说,它在同一进程中运行,并且不适用于其他应用程序中的组件),那么建议的方法是创建Binder类的子类,并扩展它以为服务提供接口。
本地绑定服务可以通过将适当配置的Binder对象传递给客户端来与绑定客户端进行通信。这是通过在绑定服务类中创建一个Binder子类,并通过添加一个或多个客户端可以调用的新方法来扩展它来实现的。在大多数情况下,这仅仅涉及实现一种返回对绑定服务实例的引用的方法。通过引用此实例,客户端可以直接访问绑定服务中的数据和调用方法。
创建服务,可通过 Android Studio 的创建模板进行 service 的创建,可省略清单文件的配置
首先,需要声明一个Binder子类。该类将包含一个名为 getService() 的单一方法,该方法将简单地返回对当前服务对象实例的引用(由this关键字表示)。
创建一个 ServiceConnection 子类并实现 onServiceConnected() 和 onServiceDisconnected() 回调方法。
当客户端成功绑定到服务时,将调用 onServiceConnected() 方法。该方法作为参数传递给服务的 onBind() 方法返回的IBinder对象。此参数被铸造到MyLocalBinder类型的对象,然后调用绑定器对象的 getService() 方法,以获得对服务实例的引用,该实例又被分配给myService。布尔标志用于表示连接已成功建立。
当连接结束时,会调用 onServiceDisconnected() 方法,该方法只是将布尔标志设置为 false。建立连接后,下一步是修改活动以绑定到服务。这涉及创建一个意图并调用 bindService() 方法,这可以在活动的 onCreate() 方法中执行。
BoundService 类
package com.example.basepractice.base.localbroadcast;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import java.text.SimpleDateFormat;
import java.util.Date;
public class BoundService extends Service {
private final LocalBinder localBinder = new LocalBinder();
public BoundService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return localBinder;
}
public String getCurrentTime() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return (simpleDateFormat.format(new Date()));
}
public class LocalBinder extends android.os.Binder {
public BoundService getService() {
return BoundService.this;
}
}
}
绑定服务后经过修改的 activity
package com.example.basepractice.base.broadcastdemo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.example.basepractice.R;
import com.example.basepractice.base.localbroadcast.BoundService;
import com.example.basepractice.baseUI.basic.BasicActivity;
public class BroadcastDemoActivity extends BasicActivity {
private Button backButton;
private TextView getTimeText;
private Button getTimeButton;
BoundService boundService;
boolean isBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_broadcast_demo);
setupUI();
// 创建 intent 并绑定服务
Intent intent = new Intent(this, BoundService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
public void showTime(View view) {
String currentTime = boundService.getCurrentTime();
getTimeText.setText(currentTime);
}
final private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
BoundService.LocalBinder binder = (BoundService.LocalBinder) service;
boundService = binder.getService();
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
private void setupUI() {
backButton = findViewById(R.id.back);
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
backAction();
}
});
getTimeText = findViewById(R.id.bound_info_get_time);
getTimeButton = findViewById(R.id.get_time_button);
getTimeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showTime(v);
}
});
}
private void backAction() {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setAction("com.demo.broadcast");
intent.putExtra("demoData",10000);
context.sendBroadcast(intent);
}
}
绑定远程服务
客户端和本地服务之间的交互可以通过将包含对服务对象引用的 IBinder 对象返回给客户端来实现。然而,在远程服务的情况下,这种方法不起作用,因为远程服务在不同的进程中运行,因此无法直接从客户端访问。
在远程服务的情况下,必须创建 Messenger 和处理程序配置,允许在客户端和服务之间跨进程边界传递消息。
具体来说,该服务创建了一个处理程序实例,当从客户端收到消息时,该实例将被调用。在初始化方面,处理程序的工作是创建一个 Messenger 对象,而Messenger 对象反过来创建一个IBinder对象,在 onBind() 方法中返回给客户端。客户端使用此 IBinder 对象来创建 Messenger 对象的实例,然后向服务处理程序发送消息。每次客户端发送消息时,都会通过消息对象调用处理程序的 handleMessage() 方法。
与本地绑定服务一样,客户端组件需要实现 ServiceConnection 类的实例,其中包含 onServiceConnected() 和 onServiceDisconnected() 方法。同样,与本地服务一样,onServiceConnected() 方法将接收由远程服务的 onBind() 方法返回的 IBinder 对象,该对象将用于向服务器处理程序发送消息。在这个示例中,客户端是 MainActivity,其代码位于 MainActivity.java 中。加载此文件并进行修改,以添加 ServiceConnection 类以及一个变量来存储对接收的 Messenger 对象的引用,同时还有一个布尔标志来指示连接是否已建立
接下来,需要添加一些代码来绑定到远程服务。这涉及创建一个与在清单文件中声明的服务的意图过滤器相匹配的意图,然后调用 bindService()方法,将意图和对 ServiceConnection 实例的引用作为参数提供。对于此示例,此代码将在活动的 onCreate()方法中实现:
package com.example.basepractice.base.broadcastdemo;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import androidx.activity.EdgeToEdge;
import com.example.basepractice.R;
import com.example.basepractice.base.localbroadcast.RemoteService;
import com.example.basepractice.baseUI.basic.BasicActivity;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.example.basepractice.base.localbroadcast.RemoteService;
public class RemoteServiceActivity extends BasicActivity {
Messenger remoteService;
boolean isBound = false;
private Button backButton;
private TextView remoteServiceMessage;
private Button sendMessageButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_remote_service);
setupUI();
Intent intent = new Intent(context, RemoteService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
void setupUI() {
backButton = findViewById(R.id.back);
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
remoteServiceMessage = findViewById(R.id.remote_service_title);
sendMessageButton = findViewById(R.id.remote_service_button);
sendMessageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendMessage(v);
}
});
}
public void sendMessage(View view) {
if (!isBound)return;
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("message", "来自客户端的消息");
message.setData(bundle);
try {
remoteService.send(message);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
final private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
remoteService = new Messenger(service);
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
remoteService = null;
isBound = false;
}
};
}
service
package com.example.basepractice.base.localbroadcast;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
public class RemoteService extends Service {
public RemoteService() {
}
public static class IncomingHandler extends Handler {
String TAG = "RemoteService";
public IncomingHandler() {
super(Looper.getMainLooper());
}
public void handleMessage(Message msg) {
Bundle data = msg.getData();
String dataString = data.getString("message");
Log.i(TAG, "Message=" + dataString);
}
}
final Messenger messenger = new Messenger(new IncomingHandler());
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return messenger.getBinder();
}
}
测试效果