Android系统中应用程序之间不能共享内存。在android SDK中提供了4种用于跨进程通信的方式。这4种方式正好对应于android系统中4种应用程序组件:
(一)Activity
(二)Content Provider
(三)Broadcast
(四)Service
Activity可以跨进程调用其他应用程序的Activity;
Content Provider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),当然,也可以对其他应用程序的数据进行增、删、改操作;
Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通信的应用程序可以监听这些广播;
Service和Content Provider类似,也可以访问其他应用程序中的数据,但不同的是,Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通信的服务叫AIDL服务。
----------------------------------------------------------------------
(方法一)使用Activity
同进程之间的调用
Intent intent = new Intent(this , Test.class );
startActivity(intent);
‚ 跨进程访问,不需要指定Context对象和Activity的Class对象,而需要指定的是要访问的Activity所对应的Action(一个字符串)。有些Activity还需要指定一个Uri(通过Intent构造方法的第2个参数指定)。
在android系统中有很多应用程序提供了可以跨进程访问的Activity,例如,下面的代码可以直接调用拨打电话的Activity。
//Intent.ACTION_CALL表示拨打电话activity 而12345678即是传递的参数
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:12345678" );
startActivity(callIntent);
//Intent.ACTION_CALL常量的定义如下:
//public static final String ACTION_CALL = "android.intent.action.CALL" ;
如果在应用程序中要共享某个Activity,需要为这个Activity指定一个字符串ID,也就是Action,就比如上面的"android.intent.action.CALL" ,也可以将这个Action看做这个Activity的key。在其他的应用程序中只要通过这个Action就可以找到与Action对应的Activity,并通过startActivity方法来启动这个Activity。
【A工程中新建一个共享Activity】
1.在AndroidManifest.xml文件中指定Action。指定Action要使用<action>标签,并在该标签的android:name属性中指定Action
如:<activity android:name=".Main" android:label="@string/app_name" >
<intent-filter>
<action android:name="net.blogjava.mobile.MYACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
2.在AndroidManifest.xml文件中指定访问协议。在指定Uri(Intent类的第2个参数)时需要访问协议。访问协议需要使 用<data>标签的android:scheme属性来指定。如果该属性的值是“info”,那么Uri就应该是“info://Uri的主体 部分”,也就是说,访问协议是Uri的开头部分。
如:<activity android:name=".Main" android:label="@string/app_name" >
<intent-filter>
<action android:name="net.blogjava.mobile.MYACTION" />
<data android:scheme="info" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
在配置AndroidManifest.xml时要注意,不能在同一个<activity>中配置多个动作,否则会覆盖MAIN动作以使该程序无法正常启动(虽然其他应用程序调用Main是正常的)。
【B工程中调用共享的Activity】
//需要使用Intent类的第2个参数指定Uri
Intent intent = new Intent("net.blogjava.mobile.MYACTION" , Uri.parse("info://调用其他应用程序的Activity" ));
// 设置value属性值
intent.putExtra("value" , "调用成功" );
// 调用ActionActivity中的Main
startActivity(intent);
//startActivityForResult(intent, 1 ); // 1为请求码
【A工程中被调用Activity处理到被调用的事件】
public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new android.view.View.OnClickListener(){ public void onClick(View v) { Toast.makeText(Main.this , editText.getText().toString(), Toast.LENGTH_LONG).show(); } }); editText = (EditText) findViewById(R.id.edittext); // 获得其他应用程序传递过来的数据 if (getIntent().getData() != null ) { // 获得Host,也就是info://后面的内容 String host = getIntent().getData().getHost(); // 其他的应用程序会传递过来一个value值,在该应用程序中需要获得这个值 Bundle bundle = getIntent().getExtras(); String value = bundle.getString("value" ); // 将Host和Value组合在一下显示在EditText组件中 editText.setText(host + ":" + value); } }通过getIntent().getData().getHost()方法获得协议后的Uri的主体部分。这个Host只是个称谓,并不一定是主机名。读者可以将其看成是任意的字符串。从Bundle对象中获得其他应用程序传递过来的数据。
在运行B工程之前,先要安装A工程
【A工程处理结束后还可以回调B工程】
可以在B中使用startActivityForResult方法来启动A应用程序的Activity,即可获得A的返回值。
例如,可以将【B工程中调用共享的Activity】修改为下面的形式。
Intent intent = new Intent("net.blogjava.mobile.MYACTION" , Uri.parse("info://调用其他应用程序的Activity" ));
//设置value属性值
intent.putExtra("value" , "调用成功" );
//调用ActionActivity中的Main
//startActivity(intent);
startActivityForResult(intent, 1 ); // 1为请求码
将【A工程中被调用Activity处理到被调用的事件】修改为
public void onClick(View view) {
Toast.makeText(this , editText.getText().toString(), Toast.LENGTH_LONG).show();
Intent intent = new Intent();
// 设置要返回的属性值
intent.putExtra("result" , editText.getText().toString());
// 设置返回码和Intent对象
setResult(2 , intent);
// 关闭Activity
finish();
}
并在B工程中覆盖onActivityResult事件方法,接收A返回的值,
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Toast.makeText(this , "返回值:" + data.getExtras().getString("result" ),
Toast.LENGTH_LONG).show();
}
当单击A中的相应按钮后,A关闭,并显示信息提示框。
从本节的介绍可以看出,跨进程访问Activity(访问其他应用程序中的Activity)主要是通过一个Action来完成的,如果要传递数据,还需要指定一个Uri。当然,传递数据也可以通过Intent来完成。传递数据的过程可以是双向的。如果要想从调用的Activity中返回数据,就需要使用startActivityForResult方法来启动Activity了。
(方式二)使用Content Provider
Android应用程序可以使用文件或SqlLite数据库来存储数据。Content Provider提供了一种在多个应用程序之间数据共享的方式(跨进程共享数据)。应用程序可以利用Content Provider完成对数据的查询、修改、添加、删除。虽然Content Provider也可以在同一个应用程序中被访问,但这么做并没有什么意义。Content Provider存在的目的就是向其他应用程序共享数据和允许其他应用程序对数据进行增、删、改操作。
Android系统本身提供了很多Content Provider,例如,音频、视频、联系人信息等等。我们可以通过这些Content Provider获得相关信息的列表。这些列表数据将以Cursor对象返回。因此,从Content Provider返回的数据是二维表的形式。
对于访问Content Provider的程序,需要使用ContentResolver对象。该对象需要使用getContentResolver方法获得,代码如下:
ContentResolver cr = getContentResolver();
与Activity一样,Content Provider也需要与一个URI对应。每一个Content Provider可以控制多个数据集,在这种情况下,每一个数据集会对应一个单独的URI。所有的URI必须以“content://”开头。
为了程序更容易维护,也为了简化程序代码,一般将URI定义成一个常量。例如,下面的常量表示系统的联系人电话号码。
android.provider.Contacts.Phones.CONTENT_URI
【编写Content Provider的具体步骤】
1. 编写一个继承于android.content.ContentProvider的子类。该类是ContentProvider的核心类。在该类中会实现query、insert、update及delete方法。实际上调用ContentResolver类的这4个方法就是调用ContentProvider类中与之要对应的方法。在本文中只介绍query。至于insert、update、delete和query的用法类似。也是通过Uri传递参数,然后在这些方法中接收这些参数,并做进一步地处理。
2. 在AndroidManifest.xml文件中配置ContentProvider。要想唯一确定一个ContentProvider,需要指定这个ContentProvider的URI,除此之外,还需要指定URI所对应的ContentProvider类。这有些象Servlet的定义,除了要指定Servlet对应的Web地址,还要指定这个地址所对应的Servlet类。
现在来看一下Uri的具体格式,先看一下如图5所示的URI。
content://com.example.transportationprovider/trains
下面对URI的4个部分做一下解释。
A:所有的URI必须以content://开头。
B:URI中最重要的部分。该部分是Content Provider的唯一标识。对于第三方应用程序来说,该部分最后使用完整的类名(包名+类名),以确保URI的唯一性。该部分需要在AndroidManifest.xml文件中<provider>标签中定义,代码如下:
<provider name=".TransportationProvider"
authorities="com.example.transportationprovider" >
C:这部分是URI的路径(path)。表示URI中各种被请求的数据。这部分是可选的, 如果Content Provider仅仅提供一种请求的数据,那么这部分可以省略。如果Content Provider要提供多种请求数据。就需要添加多个路径,甚至是子路径。例如,“land/bus”、“land/train”、“sea/ship” 就指定了3种可能提供的数据。
D:这部分也是可选的。如果要传递一个值给Content Provider,可以通过这部分传递。当然,如果不需要传值,这部分也可以省略,省略后的URI如下所示:
content://com.example.transportationprovider/trains
本例利用了《基于android SDK1.5的英文电子词典的实现》一文中实现的电子词典程序。通过ContentProvider,将电子词典的查词功能共享成Cursor对象。这样 其他的应用程序就可以通过ContentProvider来查词英文单词了。关于英文词典的具体实现细节,读者可以通过如下的地址查看《基于android SDK1.5的英文电子词典的实现》一文。
http://www. androidsdn.com/article/show/111
在电子词典程序中需要一个DictionaryContentProvider类,该类是ContentProvider的子类。在该类中实现了query方法,并根据不同的URI来返回不同的结果。让我们先看一下DictionaryContentProvider类,然后再对这些代码做一些解 释。
public class DictionaryContentProvider extends ContentProvider{ private static UriMatcher uriMatcher; private static final String AUTHORITY = "net.blogjava.mobile.dictionarycontentprovider" ; private static final int SINGLE_WORD = 1 ; private static final int PREFIX_WORDS = 2 ; public static final String DATABASE_PATH = android.os.Environment .getExternalStorageDirectory().getAbsolutePath() + "/dictionary" ; public static final String DATABASE_FILENAME = "dictionary.db" ; private SQLiteDatabase database; static { // 添加访问ContentProvider的Uri uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "single" , SINGLE_WORD); uriMatcher.addURI(AUTHORITY, "prefix/*" , PREFIX_WORDS); } // 该方法在Activity的onCreate方法之前调用 @Override public boolean onCreate() { database = openDatabase(); return true ; } //在本例中只实现了query方法,其他的方法(insert、update和delete)与query方法的实现类似 @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor cursor = null ; switch (uriMatcher.match(uri)) { case SINGLE_WORD: // 查找指定的单词 cursor = database.query("t_words" , projection, selection, selectionArgs, null , null , sortOrder); break ; case PREFIX_WORDS: String word = uri.getPathSegments().get(1 ); // 查找以指定字符串开头的单词集合 cursor = database.rawQuery("select english as _id, chinese from t_words where english like ?" , new String[] { word + "%" }); break ; default : throw new IllegalArgumentException("<" + uri + ">格式不正确." ); } return cursor; } }
2个参数值的组件,例如,按着DictionaryContentProvider中设置的两个URI,可以分别匹配下面的两个URI。
content://net.blogjava.mobile.dictionarycontentprovider/single
content://net.blogjava.mobile.dictionarycontentprovider/prefix/wo
要注意的是,访问ContentProvider的URI必须以“content://”开头。
5. 在query方法中建议使用SQLiteDatabase对象的query方法查询。因为query方法的参数正好和DictionaryContentProvider类中的query方法的参数对应,这样使用起来比较方便。
6. 由于安装了ContentProvider的应用程序会先调用ContentProvider的onCreate方法(该方法会在Activity的onCreate方法之前调用),因此,只需要将打开或复制数据库的方法(openDatabase)放在DictionaryContentProvider类中,并在onCreate方法中调用即可。
7. 在DictionaryContentProvider类中只实现了query方法。在该方法中判断了其他应用程序发送的是哪一个Uri。并进行相应的处理。这两个Uri一个是查询指定单词的,另外一个是查询以某个字符串开头的所有单词的(用于显示单词列表)。
下面在AndroidManifest.xml文件中配置DictionaryContentProvider类。
<provider android:name="DictionaryContentProvider"
android:authorities="net.blogjava.mobile.dictionarycontentprovider" />
【调用ContentProvider】
调用ContentProvider的关键是使用getContentResolver方法来获得一个ContentResolver对象,并通过ContentResolver对象的query方法来访问ContentProvider。
首先来定义两个访问ContentProvider的常量。
public final String DICTIONARY_SINGLE_WORD_URI
= "content://net.blogjava.mobile.dictionarycontentprovider/single" ;
public final String DICTIONARY_PREFIX_WORD_URI
= "content://net.blogjava.mobile.dictionarycontentprovider/prefix" ;
然后在查询按钮的单击事件中编写如下的代码来查询单词。
public void onClick(View view) {
Uri uri = Uri.parse(DICTIONARY_SINGLE_WORD_URI);
//通过ContentProvider查询单词,并返回Cursor对象,然后的操作就和直接从数据中获得
// Cursor对象后的操作是一样的了
Cursor cursor = getContentResolver().query(uri, null , "english=?" ,
new String[]{ actvWord.getText().toString() }, null );
String result = "未找到该单词." ;
if (cursor.getCount() > 0 ) {
cursor.moveToFirst();
result = cursor.getString(cursor.getColumnIndex("chinese" ));
}
new AlertDialog.Builder(this ).setTitle("查询结果" ).setMessage(result)
.setPositiveButton("关闭" , null ).show();
}
下面是显示单词列表的代码。
public void afterTextChanged(Editable s) {
if ("" .equals(s.toString()))
return ;
Uri uri = Uri.parse(DICTIONARY_PREFIX_WORD_URI + "/" + s.toString());
// 从ContentProvider中获得以某个字符串开头的所有单词的Cursor对象
Cursor cursor = getContentResolver().query(uri, null , null , null , null );
DictionaryAdapter dictionaryAdapter = new DictionaryAdapter(this ,
cursor, true );
actvWord.setAdapter(dictionaryAdapter);
}
(方式三)使用广播Broadcast
广播是一种被动跨进程通信的方式。当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据。这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通。
【发送广告】
public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); editText = (EditText) findViewById(R.id.edittext); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new android.view.View.OnClickListener(){ public void onClick(View v) { new AlertDialog.Builder(Mainsendbroadcast.this).setMessage(editText. getText().toString()).setPositiveButton("确定" , null ).show(); // 通过Intent类的构造方法指定广播的ID Intent intent = new Intent("net.blogjava.mobile.MYBROADCAST" ); // 将要广播的数据添加到Intent对象中 intent.putExtra("text" , editText.getText().toString()); // 发送广播 sendBroadcast(intent); } }); }
发送广播并不需要在AndroidManifest.xml文件中注册,但接收广播必须在AndroidManifest.xml文件中注册receiver。
【收听广告】
public class MyReceiverMainBroadcast extends BroadcastReceiver { // 当sendbroadcast发送广播时,系统会调用onReceive方法来接收广播 @Override public void onReceive(Context context, Intent intent) { // 判断是否为sendbroadcast发送的广播 if ("net.blogjava.mobile.MYBROADCAST" .equals(intent.getAction())) { Bundle bundle = intent.getExtras(); if (bundle != null ) { String text = bundle.getString("text" ); Toast.makeText(context, "在另一个程序中成功接收广播:" + text, Toast.LENGTH_LONG).show(); } } } }当应用程序发送广播时,系统会调用onReceive方法来接收广播,并通过intent.getAction()方法返回广播的ID,也就是在发送广播时Intent构造方法指定的字符串。然后就可以从Bundle对象中获得相应的数据
最后还需要在AndroidManifest.xml文件中注册receiver,代码如下:
<receiver android:name="com.hhf.test.MyReceiverMainBroadcast" >
<intent-filter>
<action android:name="net.blogjava.mobile.MYBROADCAST"/>
</intent-filter>
</receiver>
接收广播并不依赖于程序的状态。就算程序关闭了,仍然可以接收广播。
(方式四)AIDL服务
服务(Service)是android系统中非常重要的组件。Service可以脱离应用程序运行。也就是说,应用程序只起到一个启动Service的作用。一但Service被启动,就算应用程序关闭,Service仍然会在后台运行。
android系统中的Service主要有两个作用:后台运行和跨进程通信。后台运行就不用说了,当Service启动后,就可以在Service对象中 运行相应的业务代码,而这一切用户并不会察觉。而跨进程通信是这一节的主题。如果想让应用程序可以跨进程通信,就要使用我们的AIDL服务。
AIDL的全称是Android Interface Definition Language,是一种接口定义语言。通过这种语言定义接口后,Eclipse插件(ODT)会自动生成相应的Java代码接口代码。
【开启AIDL服务】
1、定义AIDL服务的接口,在Eclipse工程的src的package目录中建立一个扩展名为aidl的文件。该文件的语法类似于Java代码。aidl文件中定义AIDL服务的接口。这个接口需要在调用AIDL服务的程序中访问。
首先建立一个android工程:aidlservice。在aidlservice工程中有一个Main类,在Main类所有的目录建立一个IMyService.aidl文件,内容如下:
package com.hhf.process;
interface IMyService {
String getValue(); // 为AIDL服务的接口方法,调用AIDL服务的程序需要调用该//方法
}
如果aidl文件的内容是正确的,保存IMyService.aidl文件后,ODT会在gen目录下产生一个IMyService.java文件,可以不必管这个文件中的内容,是由ODT自动维护的,只要修改了IMyService.aidl文件的内容,IMyService.java文件的内容就会随之改变。
2、 建立一个服务类(Service的子类)。
public class MyService extends Service {
// IMyService.Stub类是根据IMyService.aidl文件生成的类,该类中包含了接口方法(getValue)
public class MyServiceImpl extends IMyService.Stub {
@Override
public String getValue() throws RemoteException {
return "从AIDL服务获得的值.";
}
}
@Override
public IBinder onBind(Intent intent) {
// 该方法必须返回MyServiceImpl类的对象实例
return new MyServiceImpl();
}
}
3、在AndroidManifest.xml文件中配置MyService类,代码如下:
<!-- 注册服务-->
<service android:name=".MyService" >
<intent-filter>
<!-- 指定调用AIDL服务的ID -->
<action android:name="net.blogjava.mobile.aidlservice.IMyService" />
</intent-filter>
</service>
【使用AIDL服务】
首先建立一个android工程,将AIDL工程中自动生成的IMyService.java文件复制到新工程中。在调用AIDL服务之前先使用bindService方法绑定AIDL服务。bindService方法需要的ServiceConnection对象可以通过onServiceConnected方法创建。
public class MainService extends Activity{ private IMyService myService = null ; public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_service); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new android.view.View.OnClickListener(){ public void onClick(View v) { // 绑定AIDL服务 bindService(new Intent("com.hhf.process.IMyService"), serviceConnection, Context.BIND_AUTO_CREATE); } }); } // 创建ServiceConnection对象 private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 获得AIDL服务对象 myService = IMyService.Stub.asInterface(service); try{ //调用AIDL服务对象中的getValue方法,并以对话框中显示该方法的返回值 new AlertDialog.Builder(MainService.this ).setMessage( myService.getValue()).setPositiveButton("确定" , null ).show(); } catch (Exception e){} } @Override public void onServiceDisconnected(ComponentName name) {} }; }
在编写AIDL服务和客户端时要注意如下两点:
1. AIDL服务中的onBind方法必须返回AIDL接口对象(MyServiceImpl对象)。该对象也是onServiceConnected事件方法的第2个参数值。
2. bindService方法的第1个参数是Intent对象,该对象构造方法的参数需要指定AIDL服务的ID,也就是在AndroidManifest.xml文件中<service>标签的<action>子标签的android:name属性的值。
总结
以上主要介绍了4种跨进程通信的方式:Activity、Content Provider、Broadcast和AIDL Service。其中Activity可以跨进程调用其他应用程序的Activity;Content Provider可以访问其他应用程序返回的Cursor对象;Broadcast采用的是被动接收的方法,也就是说,客户端只能接收广播数据,而不能向发送广播的程序发送信息。AIDL Service可以将程序中的某个接口公开,这样在其他的应用程序中就可以象访问本地对象一样访问AIDL服务对象了。这4种跨进程通信的方式可以应用在不同的场合,如,需要显示可视化的界面时可以用Activity,需要返回记录集时可以用Content Provider,只有一方需要被通知时使用Broadcast,一方总是要去访问另一方的数据时使用AIDL。
相关推荐
U盘量产工具FLASH量产工具SM3280&3281&3282-AvidiaV0209整合版
java课程期末考试
分布式消息中间件,参考kafka,未完成
修木工施工规范及流程.docx
内容概要:本文详细介绍了VECTOR提供的MICROSAR OBD协议栈解决方案,涵盖了OBD模块、ECU支持、监控功能和服务请求等方面的内容。此外,还讨论了OBD在不同国家和地区的技术标准与法规要求,以及MICROSAR OBD解决方案的优势,如适应不同项目的需求和高度集成于AUTOSAR 4平台。 适合人群:汽车电子工程师、软件开发者、汽车制造商及相关行业从业人员。 使用场景及目标:① 适用于车辆诊断系统的开发和维护;②帮助工程师理解和掌握OBD协议的具体实施方法和应用场景;③ 提供了一个成熟、可扩展的解决方案,用于满足OBD相关标准和法规的要求。 其他说明:本文不仅提供了技术层面的详细解析,还探讨了实际操作过程中可能遇到的问题和解决方案。同时强调了屏蔽信息过载的重要性,提醒工程师保持内心平静,专注做好本职工作。
适用于 Python 的 LINE 消息 API SDK适用于 Python 的 LINE Messaging API 的 SDK。介绍适用于 Python 的 LINE Messaging API SDK 可以轻松使用 LINE Messaging API 开发机器人,您可以在几分钟内创建一个示例机器人。文档请参阅官方 API 文档了解更多信息英语https //developers.line.biz/en/docs/messaging-api/overview/日语https://developers.line.biz/ja/docs/messaging-api/overview/要求Python >= 3.9安装$ pip 安装 line-bot-sdk概要用法from flask import Flask, request, abortfrom linebot.v3 import ( WebhookHandler)from linebot.v3.exceptions import ( InvalidSig
Java字节码工程工具包Javassist 版本 3版权所有 (C) 1999-2023 Shigeru Chiba,保留所有权利。Javassist(JAVA 编程助手)使 Java 字节码操作变得简单。它是一个用于编辑 Java 字节码的类库它使 Java 程序能够在运行时定义新类并在 JVM 加载类文件时对其进行修改。与其他类似的字节码编辑器不同,Javassist 提供两个级别的 API源代码级别和字节码级别。如果用户使用源代码级别 API,他们可以编辑类文件而无需了解 Java 字节码的规范。整个 API 仅使用 Java 语言的词汇表进行设计。您甚至可以以源文本的形式指定插入的字节码Javassist 会即时编译它。另一方面,字节码级别 API 允许用户像其他编辑器一样直接编辑类文件。该软件根据 Mozilla 公共许可证版本 1.1、GNU 宽通用公共许可证版本 2.1 或更高版本或 Apache 许可证版本 2.0 分发。文件README.md 此自述文件。Changes.md 发行说明。License.html 许可证文件。tuto
本项目是基于Python语言开发的西西家居全屋定制系统,旨在为家居行业提供一个高效、智能的定制解决方案。项目涵盖了从客户需求分析、设计方案生成、材料选购到最终订单生成的全过程,力求实现家居定制的数字化和智能化。 在主要功能方面,系统具备强大的客户管理模块,能够详细记录和分析客户的定制需求。设计模块则采用先进的三维建模技术,为客户提供直观、真实的家居设计方案预览。此外,系统还整合了丰富的材料数据库,方便客户根据自身喜好和预算进行材料选择。 框架方面,项目采用了B/S架构,确保了系统的稳定性和可扩展性。后端使用Python的Django框架,前端则结合了HTML、CSS和JavaScript等技术,实现了用户界面的友好和响应速度。 开发此项目的目的,不仅是为了满足家居行业对个性化定制的需求,也为计算机相关专业的学生提供了一个实践和学习的平台,有助于提升他们的实际开发能力。
Javascript 是数字化创新的起点,是语言的基础,也是基本概念。Basecamp JavascriptJavascript 是数字化创新的起点,是语言的基础,也是基本概念。嵌套存储库,可作为启动项下待办事项的实践活动。
已弃用 — Coinbase Python APICoinbase Coinbase API V2的官方 Python 库。重要提示此库当前针对的是 API V2,而 OAuth 客户端需要 V2 权限(即wallet:accounts:read)。如果您仍在使用 API V1,请使用此库的旧版本。特征接近 100% 的测试覆盖率。支持API Key + Secret和OAuth 2身份验证。调用 API 的便捷方法 - 为您打包 JSON!自动将 API 响应解析为相关的 Python 对象。使用IPython时,所有对象都具有可制表完成的方法和属性。安装coinbase可以在PYPI上使用。使用以下命令安装pippip install coinbase或者easy_installeasy_install coinbase该库目前针对 Python 版本 2.7 和 3.4+ 进行了测试。注意此软件包名称过去是指George Sibble维护的非官方 coinbase_python 库。George 慷慨地允许我们使用此软件包
基于RBAC权限控制的基础后台
本项目是基于Python爬虫的网络小说数据分析系统的设计与实现,旨在为计算机相关专业的大学生提供一个实践平台,特别是在毕业设计和项目实战练习方面。项目通过Python强大的网络爬虫技术,从流行的网络小说网站自动抓取数据,包括书籍信息、章节内容、用户评论等。 主要功能涵盖数据采集、数据清洗、数据存储和数据分析。数据采集模块利用Scrapy等爬虫框架高效抓取网页内容;数据清洗模块确保数据的准确性和一致性;数据存储则采用MySQL等数据库系统,便于数据管理和查询;数据分析模块通过Pandas、NumPy等工具进行数据处理和分析,生成多维度的统计报告和可视化图表。 此项目不仅帮助学生掌握Python编程和网络爬虫技术,还能让他们深入了解数据分析的全过程,提升解决实际问题的能力。同时,系统的实现和应用也反映了现代信息技术在文学创作和消费领域的应用价值和潜力。
本项目是一个基于Java的在线日语培训平台的设计与实现,采用SSM框架(Spring+SpringMVC+MyBatis)进行开发,旨在为计算机相关专业的学生提供一个实践和学习的平台,同时也为日语学习者提供一个在线学习的空间。项目中主要功能涵盖了用户管理、课程管理、学习资源上传下载、在线测试与反馈等多个方面。通过该平台,教师能够轻松管理课程内容和学生信息,学生则可以随时随地访问学习资源,参与在线课程和测试,从而提高学习效率和兴趣。 在开发此项目的过程中,我们重点关注了系统的可维护性和可扩展性,确保代码结构清晰,便于后续的功能迭代和优化。此外,通过使用SSM框架,实现了前后端的分离,提高了开发效率和系统的响应速度。该项目不仅能够满足毕设的需求,还能作为Java学习者提升编程能力和实践经验的实用工具。
基于java的机票管理系统设计与实现.docx
该项目为《基于Java实现的数据结构设计源码》,共包含51个文件,主要由46个Java源文件构成,辅以2个文本文件、1个Git忽略文件、1个许可证文件以及1个XML文件,全面涵盖了数据结构设计的核心内容。
绿色食品 水稻生产操作规程.docx
他妈的 Fuck是一款出色的应用程序,其灵感来自@liamosaur 的 推文,它可以纠正以前控制台命令中的错误。The Fuck太慢了吗?试试实验性的即时模式!更多示例➜ apt-get install vimE: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?➜ fucksudo apt-get install vim [enter/↑/↓/ctrl+c][sudo] password for nvbn:Reading package lists... Done...➜ git pushfatal: The current branch master has no upstream branch.To push the current branch and set the remote
全国大学生FPGA创新设计竞赛作品 “泡罩包装药品质量在线检测平台“.zip
桃苗木质量基本要求表.docx
使用 Python 漂亮地打印表格数据,这是一个库和一个命令行实用程序。存储库从 bitbucket.org/astanin/python-tabulate 迁移而来。python-tabulate使用 Python、库和命令行实用程序漂亮地打印表格数据。该库的主要用例是轻松打印小表格只需一个函数调用,格式由数据本身引导为轻量级纯文本标记创作表格数据多种输出格式适合进一步编辑或转换混合文本和数字数据的可读表示智能列对齐、可配置数字格式、小数点对齐安装要安装 Python 库和命令行实用程序,请运行pip install tabulate命令行实用程序将在 Linux 上安装为(例如tabulate)或者在 Windows 上的 Python 安装中安装为(例如)。bin/usr/bintabulate.exeScriptsC:\Python39\Scripts\tabulate.exe您可以考虑仅为当前用户安装该库pip install tabulate --user在这种情况下,命令行实用程序将安装到 ~/.local/bin/tabula