編輯:關於Android編程
使用OpenAtlas進行插件化開發,插件的開發幾乎可以按照正常程序的開發流程進行,無需添加額外的東西。為了驗證四大組件是否能夠正常工作,這裡編寫一個插件,驗證其功能。除了四大組件外,大多數應用還有Application類。該類我們也需要進行驗證。
首先新建一個模塊,按照正常流程進行開發。新建Application類,為了方便起見,所有驗證都使用日志輸出形式。
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, Plugin named Component has init!);
Log.e(TAG, ===Plugin Application is=== + this);
}
}
Activity的驗證不再重復,前面幾篇文章都是以Activity或者Fragment為基礎的,有興趣可以轉到相關鏈接。
- Android插件化開發之OpenAtlas初體驗
- Android插件化開發之OpenAtlas生成插件信息列表
- Android插件化開發之OpenAtlas資源打包工具補丁aapt的編譯
- Android插件化開發之OpenAtlas插件適配
- Android插件化開發之解決OpenAtlas組件在宿主的注冊問題
接下來驗證Service,新建一個Service,清單文件的注冊放到最後。
public class ComponentService extends Service {
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, ===Plugin Service onCreate===);
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, ===Plugin Service onBind===);
return new BinderImpl();
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, ===Plugin Service onUnbind===);
return super.onUnbind(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, ===Plugin Service onStartCommand===);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, ===Plugin Service onDestroy===);
}
class BinderImpl extends Binder{
BinderImpl getService(){
return BinderImpl.this;
}
void testMethod(){
Log.e(TAG,BinderImpl testMethod);
}
}
}
然後是ContentProvider。都是空實現,只是輸出日志。
public class ComponentContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
Log.e(TAG,ComponentContentProvider onCreate);
return false;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Log.e(TAG,ComponentContentProvider query:+Arrays.asList(projection)+ +Arrays.asList(selectionArgs)+ +selectionArgs+ +sortOrder);
return null;
}
@Nullable
@Override
public String getType(Uri uri) {
Log.e(TAG,ComponentContentProvider getType);
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
Log.e(TAG,ComponentContentProvider insert:+values);
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.e(TAG,ComponentContentProvider delete:+selection+ + Arrays.asList(selectionArgs));
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
Log.e(TAG,ComponentContentProvider update:+values+ +selection+ +Arrays.asList(selectionArgs));
return 0;
}
}
以及廣播,廣播有兩種,一種是靜態廣播,需要在清單文件中注冊,一種是動態廣播,代碼注冊
public class ComponentBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, ===Plugin BroadcastReceiver onReceive===);
}
}
public class ComponentBroadcastDynamic extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, ===Plugin ComponentBroadcastDynamic onReceive===);
}
}
最後在插件的清單文件中進行這些組件的注冊。
data-snippet-id=ext.3d490ef9fc184d473a2aa363079dd76e data-snippet-saved=false data-codota-status=done>
編寫一個Activity驗證所有功能,Activity的布局不再貼出,整個布局就是Button組成的一個布局。
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(TAG, ===Plugin MainActivity is=== + this);
findViewById(R.id.start_service).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ComponentService.class);
startService(intent);
}
});
findViewById(R.id.stop_service).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ComponentService.class);
stopService(intent);
}
});
final ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, onServiceDisconnected());
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, onServiceConnected());
ComponentService.BinderImpl binder = (ComponentService.BinderImpl) service;
ComponentService.BinderImpl bindService = binder.getService();
bindService.testMethod();
}
};
findViewById(R.id.bind_service).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ComponentService.class);
Log.i(TAG, bindService());
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
});
findViewById(R.id.unbind_service).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(conn);
}
});
findViewById(R.id.broadcast).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction(cn.edu.zafu.component);
sendBroadcast(intent);
}
});
final ComponentBroadcastDynamic componentBroadcastDynamic = new ComponentBroadcastDynamic();
findViewById(R.id.register_broadcast).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(cn.edu.zafu.component.ComponentBroadcastDynamic);
registerReceiver(componentBroadcastDynamic, intentFilter);
Log.e(TAG,ComponentBroadcastDynamic registerReceiver);
}
});
findViewById(R.id.send_broadcast_dynamic).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction(cn.edu.zafu.component.ComponentBroadcastDynamic);
sendBroadcast(intent);
}
});
findViewById(R.id.unregister_broadcast).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, ComponentBroadcastDynamic unregisterReceiver);
try{
unregisterReceiver(componentBroadcastDynamic);
}catch (Exception e){
Log.e(TAG, ComponentBroadcastDynamic has already unregister);
}
}
});
findViewById(R.id.contentprovider_insert).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String authorities = cn.edu.zafu.component.ComponentContentProvider;
Uri CONTENT_URI = Uri.parse(content:// + authorities + /test);
ContentValues values = new ContentValues();
values.put(title, title11111111);
Uri uri =MainActivity.this.getContentResolver().insert(CONTENT_URI, values);
}
});
findViewById(R.id.contentprovider_delete).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String authorities = cn.edu.zafu.component.ComponentContentProvider;
Uri CONTENT_URI = Uri.parse(content:// + authorities + /test);
int result =MainActivity.this.getContentResolver().delete(CONTENT_URI, title=?, new String[]{title11111111});
Log.e(TAG,=====+result);
}
});
findViewById(R.id.contentprovider_update).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String authorities = cn.edu.zafu.component.ComponentContentProvider;
Uri CONTENT_URI = Uri.parse(content:// + authorities + /test);
ContentValues values = new ContentValues();
values.put(title, title11111111);
int result =MainActivity.this.getContentResolver().update(CONTENT_URI, values, id=?, new String[]{1});
Log.e(TAG, ===== + result);
}
});
findViewById(R.id.contentprovider_query).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG,no impl);
}
});
}
}
按照這篇文章 Android插件化開發之OpenAtlas插件適配 進行適配工作。在build.gradle中加入flavors,讓其同時支持單獨運行以及插件運行。
productFlavors {
alone{
}
openatlas {
versionName 1.00x23
}
}
這時候我們選擇脫離插件模式運行,如圖
運行成功後,我們從上到下依次點擊按鈕,
運行後查看日志輸出。
可以看到單獨運行的時候所有功能都能正常運行。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPtXiyrG68s7Sw8fSqr2rxuTSxtaytb3L3tb31tCjrLXa0ruyvb7Nyse9q8fltaXOxLz+1tC1xMn5w/e4tNbGtb3L3tb31tCjrLKi1/bKyrWx0N64xKGjPC9wPg0KPHByZSBjbGFzcz0="brush:java;">
從以上聲明可以看出,我們的provider的聲明發生了變化,其實原因也很簡單,這裡我們做了一個橋。
而Provider需要做一些特殊處理,因為ContentProvider在Application onCreate之前初始化,因此做一個橋,告訴系統這個ContentProvider初始化完畢,都可以用了,實際上還沒完成,只是一個空實現,當需要的類能加載的時候對正常的類進行實例化。
那麼這個橋的實現是怎麼樣的呢,也很簡單,繼承ProviderProxy類,調用父類構造函數即可。調用構造函數傳遞的參數為真正的Provider的全類名。也就是原來插件的清單文件中的類名。
public class ComponentProviderBridge extends ProviderProxy{
public ComponentProviderBridge() {
super(cn.edu.zafu.component.ComponentContentProvider);
}
}
而宿主中的清單文件的類名對應變為橋的全類名。完成了以上工作後就可以將build方式修改為openAtlas的了。如圖。
生成插件後還要生成插件信息列表,按照之前的文章進行生成即可。
然後在宿主中調用插件的入口Activity
findViewById(R.id.component).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClassName(MainActivity.this, cn.edu.zafu.component.MainActivity);
startActivity(intent);
}
});
運行後點擊對應按鈕進入插件,並按之前的操作那樣,從上到下依次點擊所有按鈕測試功能。查看日志輸出。
我們會發現和單獨運行完全一樣。
最後呢,還有一個細節問題需要自己注意一下,如果你在宿主中單獨使用反射調用插件中的Fragment,如果不經過插件的四大組件,比如Activity,那麼插件的Application將不會被調用,這裡提供一種解決方法,就是手動進行Bundle的啟動,在反射前進行調用,代碼如下
BundleImpl bundle = (BundleImpl)Atlas.getInstance().getBundle(xxxxxxxx);
bundle.startBundle();
之前的文章一直在介紹OC,最近也是在找急忙慌的學習IOS,所以Android方面的知識分享就有點中斷了,但是我現在還是要靠Android吃飯,所以不能Android的工作
之前想要給statusbar和toolbar實現這樣的效果:為使得statusbar變為透明,在自定義theme中給statusbar添加了以下屬性: &l
這一節我們來看看登陸頁面怎樣布局,對於剛接觸到Android開發的童鞋來說,Android的布局感覺比較棘手,需要結合各種屬性進行設置,接下來我們由點入面來 了解安卓中頁
本文實例講述了Android編程實現二級下拉菜單及快速搜索的方法。分享給大家供大家參考,具體如下:一、我們要做什麼?上面有個搜索框,下面是一個二級下拉菜單。輸入查詢內容,