首页 文章 精选 留言 我的

精选列表

搜索[组件化],共10000篇文章
优秀的个人博客,低调大师

【微服务No.4】 API网关组件Ocelot+Consul

介绍: Ocelot是一个.NET API网关。该项目针对的是使用.NET运行微服务/面向服务架构的人员,他们需要一个统一的入口进入他们的系统。然而,它可以处理任何说HTTP并在ASP.NET Core支持的任何平台上运行的任何东西。 Ocelot是一组按特定顺序的中间件,Ocelot操纵HttpRequest对象进入由其配置指定的状态,直到它到达请求生成器中间件,在该中间件中创建HttpRequestMessage对象,该对象用于向下游服务发出请求。提出请求的中间件是Ocelot管道中的最后一件事。它不叫下一个中间件。来自下游服务的响应存储在每个请求作用域存储库中,并在请求返回到Ocelot管道时进行恢复。有一件中间件将HttpResponseMessage映射到HttpResponse对象上,并返回给客户端。这基本上是与其他一些功能。 Ocelot只能用于.NET Core,并且目前已经构建到netstandard2.0。所有下面我们使用.NET Core 2.1做演示。 创建一个基本示例: 首先我们创建一个.NET Core 2.1空项目。 当然我们还是要先引用的拉,Nuget命令行:Install-Package Ocelot 配置:添加一个json文件实现最基本的配置: { "ReRoutes": [], "GlobalConfiguration": { "BaseUrl": "urladdress" } } 这里最重要的是BaseUrl。Ocelot需要知道它正在运行的URL,以便执行标题查找和替换以及某些管理配置。当设置这个URL时,它应该是客户端将看到的Ocelot运行的外部URL。 然后我们将刚才的配置文件加入到ASP.NET Core Configuration:Program.cs public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, builder) => { builder .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) .AddJsonFile("ocelot.json"); }) .UseStartup<Startup>(); View Code 最后在添加服务以及设置中间件:Startup.cs public void ConfigureServices(IServiceCollection services) { services.AddOcelot();//添加ocelot服务 } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseOcelot().Wait();//设置所有的Ocelot中间件 app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); } } View Code 这些就是基本的所需编程代码。 配置文件的详细分析: Ocelot的主要功能是收取HTTP请求并将它们转发到下游服务。目前以另一个http请求的形式出现。Ocelot描述了将一个请求作为ReRoute路由到另一个请求。为了在Ocelot中获得任何工作,您需要在配置中设置ReRoute。 说道这里我们补充一下刚才写的json文件的两个根节点:ReRoutes和GlobalConfiguration。 ReRoutes:是一个数组,其中的每一个元素代表了一个路由,我们可以针对每一个路由进行以上功能配置,告诉Ocelot如何处理上游请求的对象。 GlobalConfiguration:全局配置,可以适当的节约配置,比如baseurl节点,服务发现配置。 这样我们就实现了通过配置文件可以完成对Ocelot的功能配置:路由、服务聚合、服务发现、认证、鉴权、限流、熔断、缓存、Header头传递等。 配置一个示例:下面这个配置信息就是将用户的请求 /ProductService/1转发到 localhost:8001/api/Test/1 { "ReRoutes": [ { "DownstreamPathTemplate": "/api/Test/{postId}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "127.0.0.1", "Port": 8001 } ], "UpstreamPathTemplate": "/ProductService/{postId}", "UpstreamHttpMethod": [ "Get", "Delete" ] } ], "GlobalConfiguration": { // "BaseUrl": "http://127.0.0.1:8887/" } } View Code DownstreamPathTemplate:下游方位url路径 DownstreamScheme:下游服务http schema DownstreamHostAndPorts:下游服务的地址,如果使用LoadBalancer的话这里可以填多项 UpstreamPathTemplate:上游也就是用户输入的请求Url模板 UpstreamHttpMethod:上游请求http方法,可使用数组:Get ,Delete等 好了这样就实现了一个基本的Ocelot网关的转发示例。 下面让我们来看一下效果吧: 首先我们运行起来webapi项目发布在8001端口。然后访问地址是:http://127.0.0.1:8001/api/Test/5 我们看到的结果是: 然后我们启动我们的网关服务;发布在端口8888下,根据以上配置我们可以看到方位地址为:http://127.0.0.1:8888/ProductService/5 然后同样的请求结果是: 这样我们就实现使用统一网关来访问不同的地址,以便我们以后实现微服务的分发部署,虽然是不是多个接口,但是我们给上游访问还是提供一个接口,我们内部实现访问该访问那个接口。 至于具体怎发布也可参考这篇文章:http://www.cnblogs.com/yanbigfeg/p/9198345.html 路由小知识: UpstreamHost=>"UpstreamHost": "baidu.com":上游主机 此功能允许您基于上游主机进行ReRoutes。这通过查看客户端使用的主机头来工作,然后将其用作我们用来识别ReRoute的信息的一部分。这样就是显示了只有在主机头值为baidu.com时才会匹配。 Priority=>"Priority": 0:优先级 此功能设置访问路由的优先级,假设在同一个路由下有多个路由,会根据优先级匹配优先级最高的,0是最低的。 Dynamic Routing:动态路由 这个主要是为了服务发现而实现的,在这种模式下,Ocelot将使用上游路径的第一个分段来查找服务发现提供商的下游服务。官网给出的大概配置效果: { "ReRoutes": [], "Aggregates": [], "GlobalConfiguration": { "RequestIdKey": null, "ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8510, "Type": null, "Token": null, "ConfigurationKey": null }, "RateLimitOptions": { "ClientIdHeader": "ClientId", "QuotaExceededMessage": null, "RateLimitCounterPrefix": "ocelot", "DisableRateLimitHeaders": false, "HttpStatusCode": 429 }, "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 0, "DurationOfBreak": 0, "TimeoutValue": 0 }, "BaseUrl": null, "LoadBalancerOptions": { "Type": "LeastConnection", "Key": null, "Expiry": 0 }, "DownstreamScheme": "http", "HttpHandlerOptions": { "AllowAutoRedirect": false, "UseCookieContainer": false, "UseTracing": false } } } View Code Ocelot实现多个端口的轮询: 以上实现的这个有什么用啊,单独发布了接口,然后使用另外一个接口去复制他吗?别急,这只是其中的一个基本使用,现在我们有了基本步骤,我们改一改,实现webapi发布两个接口,8001,8002.然后还使用网关地址访问,可以循环的访问到8001端口和8002端口。 说起来简单,做起来也简单,我们只需要在我们上面的配置上修改一下即可: { "ReRoutes": [ { "DownstreamPathTemplate": "/api/Test/{postId}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "127.0.0.1", "Port": 8001 }, { "Host": "127.0.0.1", "Port": 8002 } ], "UpstreamPathTemplate": "/ProductService/{postId}", "UpstreamHttpMethod": [ "Get" ], "LoadBalancerOptions": { "Type": "RoundRobin" } } ], "GlobalConfiguration": { // "BaseUrl": "http://127.0.0.1:8887/" } } View Code 启动两个端口: 重复请求网关两次结果: Ocelot+ Consul: 实现目标:启动服务发现然后模拟集群发布功能,实现发布端口8001,8002后,启动服务发现,然后配置Ocelot网关。实现访问统一接口可以轮询访问8001,8002,8001,8002,...这样。然后可以在添加8003,继续规则。 实现以上目标我们不需要该我们的示例代码,只需要修改配置json文件即可: { "ReRoutes": [ { "DownstreamPathTemplate": "/api/Test/{postId}", "DownstreamScheme": "http", "UpstreamPathTemplate": "/Product123Service/{postId}", "UpstreamHttpMethod": [ "Get" ], "ServiceName": "ProductService", "LoadBalancerOptions": { "Type": "RoundRobin" }, "UseServiceDiscovery": true } ], "GlobalConfiguration": { // "BaseUrl": "http://127.0.0.1:8887/" "ServiceDiscoveryProvider": { "Host": "localhost", "Port": 8500, "Type": "PollConsul", "PollingInterval": 100 } } } View Code 这个就是我们的服务功能: Ocelot允许您指定服务发现提供程序,并使用它来查找Ocelot正在将请求转发给下游服务的主机和端口。目前,这仅在GlobalConfiguration部分中受支持,这意味着将为所有的ReRoute使用相同的服务发现提供程序,以便在ReRoute级别指定ServiceName。 ServiceName:consul的服务名称 LoadBalancerOptions:使用的算法,目前有两种RoundRobin(轮询方式)和LeastConnection(最小连接) UseServiceDiscovery:是否启用服务发现功能true:为启动 ServiceDiscoveryProvider:配置服务发现的一些配置 Host:主机地址 Port:端口 PollingInterval:轮询的间隔时间,以毫秒为单位。并告诉Ocelot多久可以向Consul调用服务配置的更改 想要了解更多可以访问Ocelot官网:http://ocelot.readthedocs.io/en/latest/features/servicediscovery.html 系列目录: 微服务系列文章主要介绍微服务所使用到的一些技术和一些技术示例: 微服务——微服务的介绍和目录 微服务——【Consul】服务发现在windows下简单使用(一) 微服务——【polly】微服务故障处理库(二) 微服务——动态代理AspectCore的使用(三) 微服务——网关Ocelot+Consul实现集群轮询(四) 作者:YanBigFeg —— 颜秉锋 出处:http://www.cnblogs.com/yanbigfeg 本文版权归作者和博客园共有,欢迎转载,转载请标明出处。如果您觉得本篇博文对您有所收获,觉得小弟还算用心,请点击右下角的 [推荐],谢谢!

优秀的个人博客,低调大师

Android SDK 安装中组件的离线安装方法 (share)

这次安装在Android开发环境搭建及配置phoneGap中,搜到了一下资料,留个备份。 源地址:http://anlab-qiao.blog.sohu.com/190769011.html 一、迅雷下载地址 资源 https://dl-ssl.google.com/android/repository/xxx.zip , xxx用以下包替换。 API 3 android-1.5_r04-windows.zip android-1.5_r04-macosx.zip android-1.5_r04-linux.zipAPI 4 android-1.6_r03-windows.zip android-1.6_r03-linux.zip android-1.6_r03-macosx.zip API 5 android-2.0_r01-linux.zip android-2.0_r01-macosx.zip android-2.0_r01-windows.zip API 6 android-2.0.1_r01-linux.zip android-2.0.1_r01-macosx.zip android-2.0.1_r01-windows.zip API 7 android-2.1_r03-linux.zip(三种平台共用) API 8 android-2.2_r03-linux.zip(三种平台共用) API 9 android-2.3.1_r02-linux.zip(三种平台共用)API 10android-2.3.3_r02-linux.zip(三种平台共用) API 11 android-3.0_r02-linux.zip(三种平台共用)API 12 android-3.1_r03-linux.zip(三种平台共用) API 13 android-3.2_r01-linux.zip(三种平台共用) API 14 android-14_r01.zip(三种平台共用) sysimg_armv7a-14_r01.zip 2.2 Android SDK Platform-tools revision 7platform-tools_r07-windows.zip platform-tools_r07-linux.zip platform-tools_r07-macosx.ziprevision 8platform-tools_r08-windows.zip platform-tools_r08-linux.zip platform-tools_r08-macosx.zip 2.3 Android SDK Tools revision 12tools_r12-windows.zip tools_r12-linux.zip tools_r12-macosx.ziprevision 13tools_r13-windows.zip tools_r13-linux.zip tools_r13-macosx.ziprevision 14tools_r14-windows.zip tools_r14-linux.zip tools_r14-macosx.zip 2.4 Android SDK Docs for Android API X, revision Y docs-3.2_r01-linux.zip docs-14_r01.zip Android SDK Samples for Android API X, revision Ysamples-2.1_r01-linux.zip samples-2.2_r01-linux.zip samples-2.3_r01-linux.zip samples-2.3.3_r01-linux.zip samples-3.0_r01-linux.zip samples-3.1_r01-linux.zip samples-3.2_r01-linux.zip samples-14_r01.zip 二、将下载的压缩包放入temp文件夹下 例如:D:\ProgramFiles\android-sdk-windows\temp 三、点击SDK Manaer.exe,让其自动解压缩。 四、配置环境变量 PATH =D:\ProgramFiles\android-sdk-windows\tools SDK安装完成 本文转自挨踢前端博客园博客,原文链接http://www.cnblogs.com/duanhuajian/archive/2012/10/21/2732883.html如需转载请自行联系原作者 @挨踢前端

优秀的个人博客,低调大师

android 49 广播接收者中启动其他组件

main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/btnStartActivity" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="启动 activity" /> <Button android:id="@+id/btnStartService" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="启动service" /> <Button android:id="@+id/btnStopService" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="停止 service" /> </LinearLayout> mainActivity.java package com.sxt.day07_05; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; public class MainActivity extends Activity implements OnClickListener{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setListener(); } private void setListener() { findViewById(R.id.btnStartActivity).setOnClickListener(this); findViewById(R.id.btnStartService).setOnClickListener(this); findViewById(R.id.btnStopService).setOnClickListener(this); } @Override public void onClick(View v) { Intent intent=new Intent(); switch (v.getId()) { case R.id.btnStartActivity: intent.setAction("com.sxt.day07_05.start_activity");//发送一条广播,被MyReceiver接收到, break; case R.id.btnStartService: intent.setAction("com.sxt.day07_05.start_service"); break; case R.id.btnStopService: intent.setAction("com.sxt.day07_05.stop_service"); break; } sendBroadcast(intent);//发送广播 } } 广播接收者: package com.sxt.day07_05; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) {//收到广播 String action=intent.getAction(); Intent intent2=null; if(action.equals("com.sxt.day07_05.start_activity")){ //启动SecondActivity intent2=new Intent(context, SecondActivity.class);//context是上下文,就是发送广播的Activity intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//标志,一个Activity启动另一个Activity不用这个,因为2个Activity处于同一个任务栈,广播接收者没有任务栈,所以必出把SecondActivity启动在一个新的任务栈。因为每个Activity都在任务栈里面。 context.startActivity(intent2); }else if(action.equals("com.sxt.day07_05.start_service")){ intent2=new Intent(context, MyService.class); context.startService(intent2);//启动service }else if(action.equals("com.sxt.day07_05.stop_service")){ intent2=new Intent(context, MyService.class); context.stopService(intent2);//停止service } } } 广播接收者启动的service: package com.sxt.day07_05; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.SystemClock; import android.util.Log; public class MyService extends Service { boolean mLooper=true;//true:循环继续 @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override //service是一个后台进程,onBind,onStartCommand,onDestroy以on开头的方法都是在主线程执行的,所以为了不占用主线程的时间,这些方法里面的代码都要开辟工作线程执行。 public int onStartCommand(Intent intent, int flags, int startId) { //耗时操作都要在工作线程里面写 //即使这个service停止了,但是这个工作线程仍然不会停, //在Activity和service写的工作线程,即使Activity和service销毁了,这个工作线程还在执行。 new Thread(){ public void run() { while(mLooper){ SystemClock.sleep(1000); Log.i("main","service is loop..."); } }; }.start(); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); mLooper=false;//service销毁工作线程不会停止,因此要mLooper=false } } 广播接收者启动的Activity: package com.sxt.day07_05; import android.os.Bundle; import android.app.Activity; import android.view.Menu; public class SecondActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.second, menu); return true; } } <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".SecondActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="SecondActivity" /> </RelativeLayout> 系统描述文件: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.sxt.day07_05" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.sxt.day07_05.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name="com.sxt.day07_05.MyReceiver" > 一个广播接收者接收3个action,3个字符串,3个频道的广播, <intent-filter> <action android:name="com.sxt.day07_05.start_activity" /> <action android:name="com.sxt.day07_05.start_service" /> <action android:name="com.sxt.day07_05.stop_service" /> </intent-filter> </receiver> <service android:name="com.sxt.day07_05.MyService" /> 声明service <activity 声明activity android:name="com.sxt.day07_05.SecondActivity" android:label="@string/title_activity_second" > </activity> </application> </manifest> 本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/4892864.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android应用程序组件Content Provider应用实例(4)

程序使用到的界面文件定义在res/layout目录下,其中,main.xml文件定义MainActivity的界面,它的内容如下所示: <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="bottom"> <ListView android:id="@+id/listview_article" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:background="@drawable/border" android:choiceMode="singleChoice"> </ListView> <LinearLayout android:orientation="horizontal" android:layout_height="wrap_content" android:layout_width="match_parent" android:gravity="center" android:layout_marginTop="10dp"> <Button android:id="@+id/button_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="15dp" android:paddingRight="15dp" android:text="@string/add"> </Button> </LinearLayout> </LinearLayout> item.xml文件定义了ListView中每一个文章信息条目的显示界面,它的内容如下所示: <?xmlversion="1.0"encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textview_article_title" android:layout_width="fill_parent" android:layout_height="wrap_content"> </TextView> <TextView android:id="@+id/textview_article_abstract" android:layout_width="fill_parent" android:layout_height="wrap_content"> </TextView> <TextView android:id="@+id/textview_article_url" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp"> </TextView> </LinearLayout> article.xml文件定义了ArticleActivity的界面,它的内容如下所示: <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center"> <LinearLayout android:orientation="horizontal" android:layout_height="wrap_content" android:layout_width="fill_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="24dp" android:text="@string/title"> </TextView> <EditText android:id="@+id/edit_article_title" android:layout_width="fill_parent" android:layout_height="wrap_content"> </EditText> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_height="wrap_content" android:layout_width="fill_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/abs"> </TextView> <EditText android:id="@+id/edit_article_abstract" android:layout_width="fill_parent" android:layout_height="wrap_content"> </EditText> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_height="wrap_content" android:layout_width="fill_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="27dp" android:text="@string/url"> </TextView> <EditText android:id="@+id/edit_article_url" android:layout_width="fill_parent" android:layout_height="wrap_content"> </EditText> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_height="wrap_content" android:layout_width="match_parent" android:gravity="center" android:layout_marginTop="10dp"> <Button android:id="@+id/button_modify" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/modify"> </Button> <Button android:id="@+id/button_delete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/delete"> </Button> <Button android:id="@+id/button_add_article" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="16dp" android:paddingRight="16dp" android:text="@string/add"> </Button> <Button android:id="@+id/button_cancel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/cancel"> </Button> </LinearLayout> </LinearLayout> 在res/drawable目录下,有一个border.xml文件定义了MainActivity界面上的ListView的背景,它的内容如下所示: <?xmlversion="1.0"encoding="utf-8"?> <shapexmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solidandroid:color="#ff0000ff"/> <strokeandroid:width="1dp" android:color="#000000"> </stroke> <paddingandroid:left="7dp" android:top="7dp" android:right="7dp" android:bottom="7dp"> </padding> <cornersandroid:radius="10dp"/> </shape> 程序使用到的字符串资源文件定义在res/values/strings.xml文件中,它的内容如下所示: <?xmlversion="1.0"encoding="utf-8"?> <resources> <stringname="app_name">Article</string> <stringname="article">Article</string> <stringname="add">Add</string> <stringname="modify">Modify</string> <stringname="delete">Delete</string> <stringname="title">Title:</string> <stringname="abs">Abstract:</string> <stringname="url">URL:</string> <stringname="ok">OK</string> <stringname="cancel">Cancel</string> </resources> 本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966944,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android应用程序组件Content Provider应用实例(5)

接下来再来看程序的配置文件AndroidManifest.xml: <?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="shy.luo.article" android:versionCode="1" android:versionName="1.0"> <applicationandroid:icon="@drawable/icon"android:label="@string/app_name"> <activityandroid:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".ArticleActivity" android:label="@string/article"> </activity> </application> </manifest> 编译脚本Android.mk的内容如下所示: LOCAL_PATH:=$(callmy-dir) include$(CLEAR_VARS) LOCAL_MODULE_TAGS:=optional LOCAL_STATIC_JAVA_LIBRARIES:=libArticlesProvider LOCAL_SRC_FILES:=$(callall-subdir-java-files) LOCAL_PACKAGE_NAME:=Article include$(BUILD_PACKAGE) ################################################### include$(CLEAR_VARS) LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES:=libArticlesProvider:./libs/ArticlesProvider.jar include$(BUILD_MULTI_PREBUILT) 这个编译脚本包含了两个部分的指令,一个是把libs目录下的预编译静态库ArticlesProvider.jar编译成一本地静态库libArticlesProvider,它的相关库文件保存在out/target/common/obj/JAVA_LIBRARIES/libArticlesProvider_intermediates目录下;另一个就是编译我们的程序Article了,它通过LOCAL_STATIC_JAVA_LIBRARIES变量来引用前面的libArticlesProvider库,这个库包含了所有我们用来访问ArticlesProvider这个Content Provider中的数据的常量。 下面我们就可以编译和打包这个应用程序了: USER-NAME@MACHINE-NAME:~/Android$mmmpackages/experimental/Article USER-NAME@MACHINE-NAME:~/Android$makesnod 这样,打包好的Android系统镜像文件system.img就包含我们这里所创建的Article应用程序了。 最后,就是运行模拟器来运行我们的例子了。关于如何在Android源代码工程中运行模拟器,请参考 在Ubuntu上下载、编译和安装Android最新源代码 一文。 执行以下命令启动模拟器: USER-NAME@MACHINE-NAME:~/Android$emulator 这个应用程序的主界面如下图所示: 在前一个界面的文件列表中,点击某一个文章条目,便可以更新或者删除文章信息条目: 这样,Content Provider的使用实例就介绍完了。这篇文章的目的是使读者对Content Provider有一个大概的了解和感性的认识,在下一篇文章中,我们将详细介绍Article应用程序是如何获得ArticlesProvider这个ContentProvider接口的,只有获得了这个接口之后,Article应用程序才能访问ArticlesProvider的数据,敬请关注。 本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966946,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册