第三方服务之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; } }