Flutter和Android中的Intent
- 一、Android
- (一)Activity
- 1、显式Intent
- 2、隐式Intent
- 3、Intent的更多用法
- 使用步骤
- (一)路由与导航
- (二)在Flutter中处理来自外部应用程序传入的Intents
- (三)startActivityForResult
Intent 是一个消息传递对象,使用它可以向其他Android组件请求操作,其基本用途如:启动 Activity、启动服务、传递广播等。
Flutter中虽然没有Intent的概念,但可以通过 Flutter的intent插件 来集成Intent的功能,其页面跳转等的实现也与Android的intent类似。
最常见的就是点击按钮跳转页面的事件,下文中的Intent也可以添加在点击事件中查看效果,创建点击事件可以看这里。
一、Android
(一)Activity
1、显式Intent
(1)最简单常用的方式Intent intent = new Intent(this, SecondActivity.class);startActivity(intent);(2)setComponent()方法//第一个参数是被打开APP的包名,第二个参数是SecondActivity这个页面所在的全路径、也可以理解为包名+activity名ComponentName cName = new ComponentName(\"com.example.test\", \"com.example.test.SecondActivity\");Intent intent = new Intent();intent.setComponent(cName);//上述代码也可以是intent.setComponent(new ComponentName(\"com.example.test\",\"com.example.test.SecondActivity\"));startActivity(intent);(3)setClass()/setClassName()方法Intent intent = new Intent();intent.setClass(this, SecondActivity.class);//或者intent.setClassName(this, \"com.example.app.SecondActivity\");//或者intent.setClassName(this.getPackageName(),\"com.example.app.SecondActivity\");startActivity(intent);
2、隐式Intent
隐式Intent,即不明确指定启动哪个Activity,而是通过设置action、category、data等抽象信息,让系统来找出合适的Activity。
(1)先在AndroidManifest.xml中找到你想要调用的Activity(被Intent调用的),然后添加或修改类似下列<intent-filter>的内容:<activityandroid:name=\"com.example.app.SecondActivity\"><intent-filter><action android:name=\"Second\"/> //为了防止应用程序之间互相影响,一般的标准命名方式是包名+Action名,例如这里就应该改成\"com.example.test.SecondActivity\"。<category android:name=\"android.intent.category.DEFAULT\"/> //至少必须要有这个category才能响应</intent-filter></activity>(2)Intent创建Intent intent = new Intent();intent.setAction(\"Second\");startActivity(intent);(3)每个Intent只能指定一个action,但却可以指定多个category,需要在上述(1)(2)的AndroidManifest.xml和Intent中修改如下:<activityandroid:name=\"com.example.app.SecondActivity\"><intent-filter><action android:name=\"Second\"/><category android:name=\"android.intent.category.DEFAULT\"/><category android:name=\"com.example.text.addcategory.ADD\"/></intent-filter></activity>Intent intent = new Intent();intent.setAction(\"Second\");intent.addCategory(\"com.example.text.addcategory.ADD\");startActivity(intent);
3、Intent的更多用法
Intent对象大致包括7个属性:Action(动作)、Category(类别)、Data(数据)、Type(数据类型)、Component(组件)、Extra(扩展信息)、Flag(标志位),可以用于在不同页面之间传递参数、调用手机系统内其他应用程序、打开网页等等很多功能。
Activity的Action类型 | 作用 |
---|---|
ACTION_MAIN | 表示程序入口 |
ACTION_DAIL | 跳转至拨号界面 |
ACTION_CALL | 直接拨号(需要先添加权限) |
… | … |
Broadcast的Action类型 | 作用 |
---|---|
ACTION_TIME_TICK | 当前时间改变,并即时发送时间,只能通过系统发送。调用格式\”android.intent.action.TIME_TICK\” |
ACTION_TIME_CHENGED | 设置时间。调用格式\”android.intent.action.TIME_SET\” |
(更多属性的类型和用法可查看这里)
(二)IntentService
Service一般用于处理一些后台进程(不是线程)。IntentService则是继承并处理异步请求的一个类,可以看做Service和HandlerThread的结合体,在完成了使命之后会自动停止,适合需要在工作线程处理UI无关任务、后台耗时较多的场景。
使用步骤
1、自定义LocalIntentService继承自IntentService。
2、实现onHandleIntent(), 用于实现任务逻辑。
public class MyIntentService extends IntentService{public MyIntentService(String name) {super(name);}@Overrideprotected void onHandleIntent(@Nullable Intent intent) {String action = intent.getStringExtra(\"task_action\");Log.d(\"IntentService\", \"receive task :\" + action);SystemClock.sleep(2000); //即使第一个任务休眠,后续的任务也会等待其执行完毕再执行if(\"com.example.action.TASK1\".equals(action)){Log.d(\"IntentService\", \"handle task :\" + action);//运行时可以在控制台看到Log打印的日志}}}
3、启动IntentService。
Intent intentService = new Intent(this, MyIntentService.class);intentService.putExtra(\"tast_action\", \"com.example.action.TASK1\");startService(service);intentService.putExtra(\"tast_action\", \"com.example.action.TASK2\");startService(service);intnetService.putExtra(\"tast_action\", \"com.example.action.TASK3\");startService(service);
二、Flutter
Flutter不具有Intents的概念,但如果需要的话,Flutter可以通过Native整合来触发Intents,也可以集成Intent插件来调用外部组件。
(一)路由与导航
要在Flutter中切换屏幕,可以访问路由以绘制新的Widget。 管理多个屏幕有两个核心概念和类:Route 和 Navigator。Route是应用程序的“屏幕”或“页面”的抽象(可以认为是Activity), Navigator是管理Route的Widget。Navigator可以通过push和pop route以实现页面切换。
和Android在AndroidManifest.xml中声明Activitiy类似,在Flutter中,可以将具有指定Route的Map传递到顶层MaterialApp实例:
void main() {runApp(new MaterialApp(home: new MyAppHome(), // becomes the route named \'/\'routes: <String, WidgetBuilder> {\'/a\': (BuildContext context) => new MyPage(title: \'page A\'),\'/b\': (BuildContext context) => new MyPage(title: \'page B\'),\'/c\': (BuildContext context) => new MyPage(title: \'page C\'),},));}
然后,就可以在需要的地方通过Navigator来切换到命名路由的页面:
Navigator.of(context).pushNamed(\'/b\');
(二)在Flutter中处理来自外部应用程序传入的Intents
Flutter可以通过直接与Android层通信并请求共享的数据来处理来自Android的Intents。
在这个例子中,我们注册文本共享intent,所以其他应用程序可以共享文本到我们的Flutter应用程序
这个应用程序的基本流程是我们首先处理Android端的共享文本数据,然后等待Flutter请求数据,然后通过MethodChannel发送。
首先像隐式Intent一样在AndroidManifest.xml中注册我们想要处理的intent:
<activityandroid:name=\".MainActivity\"android:launchMode=\"singleTop\"android:theme=\"@style/LaunchTheme\"android:configChanges=\"orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection\"android:hardwareAccelerated=\"true\"android:windowSoftInputMode=\"adjustResize\"><!-- This keeps the window background of the activity showinguntil Flutter renders its first frame. It can be removed ifthere is no splash screen (such as the default splash screendefined in @style/LaunchTheme). --><!-- 这将保持活动的窗口背景显示直到Flutter呈现出它的第一帧。如果没有启动屏幕(例如默认启动屏幕在@style/LaunchTheme中定义)。 --><meta-dataandroid:name=\"io.flutter.app.android.SplashScreenUntilFirstFrame\"android:value=\"true\" /><intent-filter><action android:name=\"android.intent.action.MAIN\"/><category android:name=\"android.intent.category.LAUNCHER\"/></intent-filter><intent-filter><action android:name=\"android.intent.action.SEND\" /><category android:name=\"android.intent.category.DEFAULT\" /><data android:mimeType=\"text/plain\" /></intent-filter></activity>
然后,在MainActivity中处理intent,一旦我们从intent中获得共享文本数据,我们就会持有它,直到Flutter在完成准备就绪时请求它:
package com.example.flutterintent;import android.content.Intent;import android.os.Bundle;import java.nio.ByteBuffer;import io.flutter.app.FlutterActivity;import io.flutter.plugin.common.ActivityLifecycleListener;import io.flutter.plugin.common.MethodCall;import io.flutter.plugin.common.MethodChannel;import io.flutter.plugins.GeneratedPluginRegistrant;public class MainActivity extends FlutterActivity {String sharedText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);GeneratedPluginRegistrant.registerWith(this);Intent intent = getIntent();String action = intent.getAction();String type = intent.getType();if (Intent.ACTION_SEND.equals(action) && type != null) {if (\"text/plain\".equals(type)) {handleSendText(intent); // Handle text being sent}}new MethodChannel(getFlutterView(), \"app.channel.shared.data\").setMethodCallHandler(new MethodChannel.MethodCallHandler() {@Overridepublic void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {if (methodCall.method.contentEquals(\"getSharedText\")) {result.success(sharedText);sharedText = null;}}});}void handleSendText(Intent intent) {sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);}}
最后,就可以在渲染Flutter视图时请求数据:
import \'package:flutter/material.dart\';import \'package:flutter/services.dart\';void main() {runApp(new SampleApp());}class SampleApp extends StatelessWidget {// This widget is the root of your application.@overrideWidget build(BuildContext context) {return new MaterialApp(title: \'Sample Shared App Handler\',theme: new ThemeData(primarySwatch: Colors.blue,),home: new SampleAppPage(),);}}class SampleAppPage extends StatefulWidget {SampleAppPage({Key key}) : super(key: key);@override_SampleAppPageState createState() => new _SampleAppPageState();}class _SampleAppPageState extends State<SampleAppPage> {static const platform = const MethodChannel(\'app.channel.shared.data\');String dataShared = \"No data\";@overridevoid initState() {super.initState();getSharedText();}@overrideWidget build(BuildContext context) {return new Scaffold(body: new Center(child: new Text(dataShared)));}getSharedText() async {var sharedData = await platform.invokeMethod(\"getSharedText\");if (sharedData != null) {setState(() {dataShared = sharedData;});}}}
(三)startActivityForResult
在Android中,startActivityForResult用于启动一个Activity并获得它返回的数据,如打开本地文件选择器等。
而处理Flutter中所有路由的Navigator类可用于从已经push到栈的路由中获取结果。 这可以通过等待push返回的Future来完成。例如,如果您要启动让用户选择其位置的位置的路由,则可以执行以下操作:
Map coordinates = await Navigator.of(context).pushNamed(\'/location\');
然后在你的位置路由中,一旦用户选择了他们的位置,你可以将结果”pop”出栈:
Navigator.of(context).pop({\"lat\":43.821757,\"long\":-79.226392});
三、部分参考资料
文中不详尽之处还望指出补充✍
Flutter中文网-Intent
AndroidDeveloper官方文档
Android Intent用法总结
Android中Service与Intent的使用比较