Android四大组件——Service——和Activity的通信
任务描述:在MyService里提供一个下载功能,然后再Activity中可以决定何时开始下载,以及随时查看下载进度。
按照之前的思路:在MyService中创建一个方法,用以对下载进行管理。然后在MainActivity中调用该方法。
1.修改布局如下:
添加了一个控制下载的按钮。
2.在MyService中添加管理下载的方法
public void startDownload(){ Toast.makeText(this,"开始下载",Toast.LENGTH_LONG).show(); }
3.在MainActivity中调用该方法
public void startDownload(View view) { MyService myService = new MyService(); myService.startDownload(); }
现在运行看看效果:
毫不意外的,崩掉了。
原因是空指针异常。
Toast.makeText(this,"开始下载",Toast.LENGTH_LONG).show();
this这里的上下文空指针异常。
不能通过该形式实现,换一个思路,借助前一篇中我们忽略的onBind()方法便可。如下:
实现思路:在MyService里创建一个专门的Binder对象来对下载进行管理。(通过绑定的形式来启动服务)
修改MyService的代码,修改后如下:
public class MyService extends Service { private static final String TAG = "MyService";
//新建DownloadBinder类,并让它继承Binder,任何在其内部提供开始下载的方法。 public class DownloadBinder extends Binder{ public void startDownload(){ Log.d("MyService","开始下载"); Toast.makeText(getApplicationContext(),"开始下载",Toast.LENGTH_LONG).show(); } } @Override public IBinder onBind(Intent intent) { return new DownloadBinder(); //将返回值修改为创建一个DownloadBinder的对象 } @Override public void onCreate() { super.onCreate(); Log.d(TAG,"onCreate"); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG,"onDestroy"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG,"onStartCommand"); return super.onStartCommand(intent, flags, startId); } }
修改MainActivity的代码,修改后如下:
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; public MyService.DownloadBinder downloadBinder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); } //开启服务 public void startService(View view) { Intent intent = new Intent(); intent.setClass(this, MyService.class); startService(intent); } //结束服务 public void stopService(View view) { Intent intent = new Intent(); intent.setClass(this, MyService.class); stopService(intent); } private ServiceConnection serviceConnection = new ServiceConnection() { //创建一个ServiceConnection的内部类,并重写里面的方法。 @Override public void onServiceConnected(ComponentName name, IBinder service) { //该方法会在Activity和Service绑定成功的时候调用。 Log.d(TAG,"onServiceConnected"); downloadBinder =(MyService.DownloadBinder) service; //通过向下转型得到了DownloadBinder的实列 downloadBinder.startDownload(); } @Override public void onServiceDisconnected(ComponentName name) { //该方法只有在Service的创建崩溃或者被杀掉的时候才会调用,并不常用。 } }; //开始下载 public void startDownload(View view) { Intent intent = new Intent(); intent.setClass(this,MyService.class); bindService(intent,serviceConnection, BIND_AUTO_CREATE);//绑定服务
//第一个参数是Intent对象,第二个参数是前面创建出来的ServiceConnection实例,
//第三个参数是一个标志位,这里的BIND_AUTO_CREATE表示在Activity和Service绑定后自动创建Service.
} }
现在来运行一下:
可以看到,以及运行成功了。
任何一个Service在整个应用程序范围内都是通用的。即MyService不仅可以和MainActivty绑定,还可以和任何一个其他的Activity进行绑定,并且在绑定完成后,它们都可以获取相同的DownloadBinder实例。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)