第三方服务之Bmob后端云的云应用收纳集小项目(五)
事先说明:这里的一切操作都是在集成了BmobSDK之后实现的,如果对Bmob还不了解的话,请关注我第一篇Bmob文章
项目上线:项目已经上线百度市场,需要的同学可下载反编来学习,应用袋:http://shouji.baidu.com/software/9529251.html
项目同时也涉及到百度自动更新组件,后续我会在我的博客中推出百度自动更新组件的集成
请关注我的CSDN博客,Hensen_的博客:http://blog.csdn.net/qq_30379689
项目意义:对于2016年Google I/O大会上提出的Instant Apps,即用户不需下载app,就可以运行app的这个新鲜的理念
聪明你的可能会联想到H5App,webApp也是如此的效果,没错,今天带大家做一个免下载,免安装,即点即用的应用收纳集
具体思路:
项目效果图:
后台数据库表的结构:(右键在新标签打开可看原图)
步骤一:javaBean的介绍
分类实体类:
public class Item {
//分类名
private String type;
//分类名下面的2个应用名
private String type_1;
private String type_2;
//根据id可排序
private int typeId;
//分类图标
private BmobFile typeIcon_file;
public String getType_1() {
return type_1;
}
public void setType_1(String type_1) {
this.type_1 = type_1;
}
public String getType_2() {
return type_2;
}
public void setType_2(String type_2) {
this.type_2 = type_2;
}
public BmobFile getTypeIcon_file() {
return typeIcon_file;
}
public void setTypeIcon_file(BmobFile typeIcon_file) {
this.typeIcon_file = typeIcon_file;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getTypeId() {
return typeId;
}
public void setTypeId(int typeId) {
this.typeId = typeId;
}
}
应用实体类:
public class More {
//应用名
private String name;
//应用图标
private BmobFile icon;
//应用跳转的H5页面
private String toUrl;
//根据pid可以排序
private int typePid;
//对应的分类
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BmobFile getIcon() {
return icon;
}
public void setIcon(BmobFile icon) {
this.icon = icon;
}
public String getToUrl() {
return toUrl;
}
public void setToUrl(String toUrl) {
this.toUrl = toUrl;
}
public int getTypePid() {
return typePid;
}
public void setTypePid(int typePid) {
this.typePid = typePid;
}
}
创建一个GridView布局(由于前面带有一个搜索栏,所以用到的是开源框架GridViewWithHeaderAndFooter):
<in.srain.cube.views.GridViewWithHeaderAndFooter
android:id="@+id/gv_home"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="2"
android:scrollbars="none"
android:verticalSpacing="12dp"
android:horizontalSpacing="-8dp"/>
创建一个View布局用于填充GridView(左边文字右边图片,可看效果图分类页):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp">
<LinearLayout
android:id="@+id/ly_type"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="@drawable/mine_common_border"
android:padding="8dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="2dp">
<TextView
android:id="@+id/tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:textColor="#000000"
android:textSize="16dp" />
<TextView
android:id="@+id/tv_type_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:textColor="#888888"
android:textSize="12dp" />
<TextView
android:id="@+id/tv_type_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:textColor="#888888"
android:textSize="12dp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_type"
android:layout_width="50dp"
android:layout_height="50dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
创建一个GridView的Adapter来适配View(这里用Xutils来加载图片,通过下面2句代码,new一个对象,display就可以了):
public class HomeAdapter extends BaseAdapter {
//模块数据
private List<Item> list;
private LayoutInflater mInflater;
private Context context;
private Item item;
private Intent intent;
private BitmapUtils bitmapUtils;
public HomeAdapter(Context context, List<Item> list) {
this.list = list;
mInflater = LayoutInflater.from(context);
this.context = context;
bitmapUtils = new BitmapUtils(context);
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.adapter_home, null);
}
final ViewHolder holder = getViewHolder(convertView);
item = list.get(position);
//模块名称
holder.tv_type.setText(item.getType());
holder.tv_type.setTag(item.getType());
holder.tv_type_1.setText(item.getType_1());
holder.tv_type_2.setText(item.getType_2());
//模块导航图片
if (item.getTypeIcon_file() != null) {
bitmapUtils.display(holder.iv_type, item.getTypeIcon_file().getFileUrl(context));
}
//模块点击事件
holder.ly_type.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
intent = new Intent(context, MoreActivity.class);
intent.putExtra("title", holder.tv_type.getTag() + "");
context.startActivity(intent);
}
});
return convertView;
}
/**
* 获得控件管理对象
*
* @param view
* @return
*/
private ViewHolder getViewHolder(View view) {
ViewHolder holder = (ViewHolder) view.getTag();
if (holder == null) {
holder = new ViewHolder(view);
view.setTag(holder);
}
return holder;
}
/**
* 控件管理类
*/
private class ViewHolder {
private TextView tv_type,tv_type_1,tv_type_2;
private LinearLayout ly_type;
private ImageView iv_type;
ViewHolder(View view) {
tv_type = (TextView) view.findViewById(R.id.tv_type);
tv_type_1 = (TextView) view.findViewById(R.id.tv_type_1);
tv_type_2 = (TextView) view.findViewById(R.id.tv_type_2);
ly_type = (LinearLayout) view.findViewById(R.id.ly_type);
iv_type = (ImageView) view.findViewById(R.id.iv_type);
}
}
}
代码填充GridView数据:
/**
* 初始化模块数据
*/
private void initItemData() {
query = new BmobQuery<>();
query.setCachePolicy(BmobQuery.CachePolicy.CACHE_THEN_NETWORK);
query.order("typeId");
query.setLimit(200);
query.findObjects(getActivity(), new FindListener<Item>() {
@Override
public void onSuccess(List<Item> object) {
itemList = object;
//显示模块数据
adapter = new HomeAdapter(getActivity(), itemList);
gv_home.setNumColumns(2);
gv_home.setAdapter(adapter);
}
@Override
public void onError(int code, String msg) {
}
@Override
public void postOnFailure(int code, String msg) {
}
});
}
这里可以关注我博客上面的有关对WebView处理的文章:http://blog.csdn.net/qq_30379689/article/details/51898640
步骤四:部分H5App出现定位功能(百度地图等),那么应该对必须解决安卓6.0系统的权限问题,将权限请求放在应用页面开启之前的页面,之后检查到H5App需要定位功能时会自动弹出权限申请,这里使用的是Bmob封装好的PermissionManager
以下是Bmob的官方说明:
Android6.0中对特定的权限进行了动态授权的方式,需要在运行时用户手动授予,如果用户拒绝后再次申请还可以向用户弹框说明权限的作用,用户点击确认后再去申请。
因此,我们提供了一个权限管理的工具类PermissionManager(cn.bmob.v3.helper)
,具体使用如下:
注:在v3.4.6
的BmobSDK内部集成PermissionManager
类,自v3.4.7
以后的SDK内部将不再提供该类,开发者可以在下载的配套官方Demo的com.example.bmobexample.permission
包下面查看该类源码。
第一步:在项目的Gradle上添加下面这些信息:
android {
compileSdkVersion 23
buildToolsVersion '23.0.2'
//**bmob-sdk:3.4.6版本依赖包,用于兼容Android6.0系统**
useLibrary 'org.apache.http.legacy'
添加依赖:
compile 'com.android.support:support-v4:23.2.1'
第二步:构建PremissionManager类
PermissionManager helper;
helper = PermissionManager.with(MainActivity.this)
//添加权限请求码
.addRequestCode(MainActivity.REQUEST_CODE_CAMERA)
//设置权限,可以添加多个权限
.permissions(Manifest.permission.ACCESS_FINE_LOCATION<span style="font-family: 'microsoft yahei';">)</span>
//设置权限监听器
.setPermissionsListener(new PermissionListener() {
@Override
public void onGranted() {
//当权限被授予时调用
Toast.makeText(MainActivity.this, "Camera Permission granted",Toast.LENGTH_LONG).show();
}
@Override
public void onDenied() {
//用户拒绝该权限时调用
Toast.makeText(MainActivity.this, "Camera Permission denied",Toast.LENGTH_LONG).show();
}
@Override
public void onShowRationale(String[] permissions) {
//当用户拒绝某权限时并点击`不再提醒`的按钮时,下次应用再请求该权限时,需要给出合适的响应(比如,给个展示对话框来解释应用为什么需要该权限)
Snackbar.make(btn_camera, "需要相机权限去拍照", Snackbar.LENGTH_INDEFINITE)
.setAction("ok", new View.OnClickListener() {
@Override
public void onClick(View v) {
//必须调用该`setIsPositive(true)`方法
helper.setIsPositive(true);
helper.request();
}
}).show();
}
})
//请求权限
.request();
第三步:覆写onResultPermissionResult方法:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_CODE_CAMERA:
helper.onPermissionResult(permissions, grantResults);
break;
}
}