HarmonyOS-实战-04
第四章:UI高级控件4.1、ListContainer列表控件ListContainer是用来呈现连续、多行数据的组件,包含一系列相同类型的列表项。有点类似Android中的ListView控件。支持的XML属性ListContainer的共有XML属性继承自:Component综合案例一:加载简单数据1、在layout目录下,AbilitySlice对应的布局文件ability_main.xml
第四章:UI高级控件
4.1、ListContainer列表控件
ListContainer是用来呈现连续、多行数据的组件,包含一系列相同类型的列表项。有点类似Android中的ListView控件。
支持的XML属性
ListContainer的共有XML属性继承自:Component
综合案例一:加载简单数据
1、在layout目录下,AbilitySlice对应的布局文件ability_main.xml文件中创建ListContainer
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<ListContainer
ohos:id="$+id:list_container"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:layout_alignment="horizontal_center"
/>
</DirectionalLayout>
2、在layout目录下新建xml文件(例:item_city.xml),作为ListContainer的子布局。
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_content"
ohos:width="match_parent"
ohos:left_margin="16vp"
ohos:right_margin="16vp"
ohos:orientation="vertical">
<Text
ohos:id="$+id:item_index"
ohos:height="match_content"
ohos:width="match_content"
ohos:padding="4vp"
ohos:text="Item0"
ohos:text_size="20fp"
ohos:layout_alignment="center"/>
<Component
ohos:height="1vp"
ohos:width="match_parent"
ohos:background_element="gray"
/>
</DirectionalLayout>
3、创建City.java类,作为ListContainer的数据包装类
package com.sudojava.listcontainerdemo.bean;
public class City {
private String name;
public City(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "City{" +
"name='" + name + '\'' +
'}';
}
}
4、ListContainer每一行可以为不同的数据,因此需要适配不同的数据结构,使其都能添加到ListContainer上。
创建CityProvider.java,继承自BaseItemProvider。必须重写的方法如下:
方法 | 作用 |
---|---|
int getCount() | 返回填充的表项个数。 |
Object getItem(int position) | 根据position返回对应的数据。 |
long getItemId(int position) | 返回某一项的id。 |
Component getComponent(int position, Component covertComponent,ComponentContainer componentContainer) | 根据position返回对应的界面组件。 |
package com.sudojava.listcontainerdemo.provider;
import com.sudojava.listcontainerdemo.ResourceTable;
import com.sudojava.listcontainerdemo.bean.City;
import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.components.*;
import java.util.List;
public class CityProvider extends BaseItemProvider {
private List<City> list;
private AbilitySlice slice;
public CityProvider(List<City> list,AbilitySlice slice){
this.list = list;
this.slice = slice;
}
@Override
public int getCount() {
return list==null?0:list.size();
}
@Override
public Object getItem(int position) {
if (list!=null&&position>=0&&position<list.size()){
return list.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public Component getComponent(int position, Component component, ComponentContainer componentContainer) {
final Component cpt;
if (component==null){
cpt = LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_item_city,null,false);
}else {
cpt = component;
}
City city = list.get(position);
Text text = (Text)cpt.findComponentById(ResourceTable.Id_item_index);
text.setText(city.getName());
return cpt;
}
}
5、在Java代码中添加ListContainer的数据,并适配其数据结构。
package com.sudojava.listcontainerdemo.slice;
import com.sudojava.listcontainerdemo.ResourceTable;
import com.sudojava.listcontainerdemo.bean.City;
import com.sudojava.listcontainerdemo.provider.CityProvider;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.ListContainer;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.ToastDialog;
import java.util.ArrayList;
import java.util.List;
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
initListContainer();
}
private void initListContainer(){
ListContainer listContainer = (ListContainer)findComponentById(ResourceTable.Id_list_container);
List<City> list = getData();
CityProvider cityProvider = new CityProvider(list,this);
listContainer.setItemProvider(cityProvider);
listContainer.setBindStateChangedListener(new Component.BindStateChangedListener() {
@Override
public void onComponentBoundToWindow(Component component) {
cityProvider.notifyDataChanged();
}
@Override
public void onComponentUnboundFromWindow(Component component) {
}
});
listContainer.setItemClickedListener(new ListContainer.ItemClickedListener() {
@Override
public void onItemClicked(ListContainer listContainer, Component component, int i, long l) {
City city = (City)listContainer.getItemProvider().getItem(i);
new ToastDialog(getContext())
.setText("you clicked:"+city.getName())
.setAlignment(LayoutAlignment.CENTER)
.show();
}
});
}
@Override
public void onActive() {
super.onActive();
}
public List<City> getData(){
List<City> list = new ArrayList<>();
for (int i = 0; i <= 40; i++) {
list.add(new City("City Name : " + i));
}
return list;
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
4.2、Json-Server服务端搭建
JSON-Server 是一个 Node 模块,运行 Express 服务器,你可以指定一个 json 文件作为 api 的数据源。
下面我们就用基于NodeJs的Json-Server,关于NodeJs在windows下的配置,大家可以百度一下。这里我就不在详细描述了。我们安装好NodeJs之后,直接可以在命令行输入以下命令来安装JSON Server:
npm install -g json-server
安装成功之后,可以在命令行终端输入:json-server来检测是否安装成功。
C:\Users\Administrator>json-server
bin.js [options] <source>
Options:
-c, --config Path to config file
[default: "json-server.json"]
-p, --port Set port [default: 3000]
-H, --host Set host [default: "localhost"]
-w, --watch Watch file(s) [boolean]
-r, --routes Path to routes file
-m, --middlewares Paths to middleware files [array]
-s, --static Set static files directory
--read-only, --ro Allow only GET requests [boolean]
--no-cors, --nc Disable Cross-Origin Resource Sharing [boolean]
--no-gzip, --ng Disable GZIP Content-Encoding [boolean]
-S, --snapshots Set snapshots directory [default: "."]
-d, --delay Add delay to responses (ms)
-i, --id Set database id property (e.g. _id)
[default: "id"]
--foreignKeySuffix, --fks Set foreign key suffix (e.g. _id as in post_id)
[default: "Id"]
-q, --quiet Suppress log messages from output [boolean]
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
Examples:
bin.js db.json
bin.js file.js
bin.js http://example.com/db.json
https://github.com/typicode/json-server
Missing <source> argument
json-server服务的启动
json-server可以直接把一个json文件托管成一个具备全RESTful风格的API,并支持跨域、jsonp、路由订制、数据快照保存等功能的 web 服务器。
db.json文件的内容格式如下:
{
"students":[
{
"sno":108,
"sname":"曾华",
"ssex":"男",
"sbirthday":"九月 1, 1996",
"classid":"95033"
},
{
"sno":105,
"sname":"匡明",
"ssex":"男",
"sbirthday":"十月 2, 1995",
"classid":"95031"
},
{
"sno":107,
"sname":"王丽",
"ssex":"女",
"sbirthday":"一月 23, 1996",
"classid":"95033"
},
{
"sno":101,
"sname":"李军",
"ssex":"男",
"sbirthday":"二月 20, 1996",
"classid":"95033"
},
{
"sno":109,
"sname":"王芳",
"ssex":"女",
"sbirthday":"二月 10, 1995",
"classid":"95031"
},
{
"sno":103,
"sname":"陆君",
"ssex":"男",
"sbirthday":"六月 3, 1994",
"classid":"95031"
}
]
}
启动命令如下:
json-server --watch --port 8080 student.json
执行结果如下:
jack@luoliwendeMacBook-Pro Documents % json-server --watch --port 8080 student.json
\{^_^}/ hi!
Loading student.json
Done
Resources
http://localhost:8080/students
Home
http://localhost:8080
Type s + enter at any time to create a snapshot of the database
Watching...
json-server的相关启动参数
- 语法:json-server [options]
参数 | 简写 | 默认值 | 说明 |
---|---|---|---|
–config | -c | 指定配置文件 | [默认值: “json-server.json”] |
–port | -p | 设置端口 [默认值: 3000] | Number |
–host | -H | 设置域 [默认值: “0.0.0.0”] | String |
–watch | -w | Watch file(s) | 是否监听 |
4.3、Ngrok 内网穿透技术
ngrok 我们可以理解为一个内网穿透的工具,是国内用的比较多的工具,什么是内网穿透呢?简言之就是将内网IP映射成对外可以访问的网址和域名。
Ngrok的官网是:https://www.ngrok.cc/ 打开官网直接注册账号,可以使用QQ号码来注册。
分别下载Windows和Mac客户端,这里ngrok提供了对Windows和Mac的支持,下载网址如:
https://www.ngrok.cc/download.html
下载好客户端了,使用终端控制台进入到执行下载的文件夹中,执行如下命令:
./sunny clientid a27ec75a06e6be46--隧道ID编号
Sunny-Ngrok 官 网 www.ngrok.cc (Ctrl+C 退 出 )
Tunnel Status online
Version 2.1/2.1
Forwarding http://sudojava.free.idcfengye.com -> 127.0.0.1:80
Web Interface 127.0.0.1:4040
# Conn 0
Avg Conn Time 0.00ms
使用浏览器访问网址:http://sudojava.free.idcfengye.com/students 结果如下:
4.4、ListContainer访问网络数据
ListContainer大部分都是请求的网络数据,比如在线的Json数据。生成在线的数据一般都是采用Web服务器来生成,比如SpringBoot、PHP或者NodeJS等服务端。
1、准备一段产品的Json数据
{
"products":[
{
"pid":1,
"pname":"联想电脑",
"price":5000,
"category_name":"电脑办公"
},
{
"pid":2,
"pname":"海尔电脑",
"price":3000,
"category_name":"电脑办公"
},
{
"pid":3,
"pname":"雷神电脑",
"price":5000,
"category_name":"电脑办公"
},
{
"pid":4,
"pname":"JACK JONES",
"price":800,
"category_name":"服装"
},
{
"pid":5,
"pname":"真维斯",
"price":200,
"category_name":"服装"
},
{
"pid":6,
"pname":"花花公子",
"price":440,
"category_name":"服装"
},
{
"pid":7,
"pname":"劲霸",
"price":2000,
"category_name":"服装"
},
{
"pid":8,
"pname":"香奈儿",
"price":800,
"category_name":"女士用品"
},
{
"pid":9,
"pname":"相宜本草",
"price":200,
"category_name":"女士用品"
},
{
"pid":10,
"pname":"面霸",
"price":5,
"category_name":"女士用品"
},
{
"pid":11,
"pname":"雪碧",
"price":56,
"category_name":"饮料饮品"
},
{
"pid":12,
"pname":"香飘飘奶茶",
"price":1,
"category_name":"饮料饮品"
}
]
}
2、生成Restful风格的json数据
在Windows系统E盘目录下,创建一个json文件夹,把上面的数据复制到一个product.json文件中。使用命令行终端进入到E盘的json目录中执行以下命令。
备注:由于HarmonyOS的远程模拟器访问本地的json数据是不支持localhost的地址,所以要将localhost地址映射到外网去,这样就会使用到上面我们介绍的ngrok,内网穿透技术。
E:\json>json-server --watch --host 127.0.0.1 --port 8080 product.json
\{^_^}/ hi!
Loading product.json
Done
Resources
http://192.168.20.23:3001/products
Home
http://192.168.20.23:3001
Type s + enter at any time to create a snapshot of the database
Watching...
GET /products 200 21.495 ms - -
3、添加布局文件
添加一个主布局ability_main.xml文件
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<ListContainer
ohos:id="$+id:product_list"
ohos:height="match_parent"
ohos:width="match_parent"/>
</DirectionalLayout>
添加一个用于ListContainer显示Item的布局文件
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_content"
ohos:width="match_parent"
ohos:orientation="vertical">
<DirectionalLayout
ohos:height="match_content"
ohos:width="match_content"
ohos:orientation="horizontal">
<Text
ohos:text="产品名称:"
ohos:text_size="15vp"
ohos:height="match_content"
ohos:left_margin="20vp"
ohos:top_margin="20vp"
ohos:text_color="black"
ohos:width="match_content"/>
<Text
ohos:id="$+id:product_name"
ohos:height="match_content"
ohos:hint="香蕉"
ohos:top_margin="20vp"
ohos:hint_color="red"
ohos:text_size="15vp"
ohos:width="match_content"/>
</DirectionalLayout>
<DirectionalLayout
ohos:height="match_content"
ohos:width="match_content"
ohos:orientation="horizontal">
<Text
ohos:text="产品价格:"
ohos:text_size="15vp"
ohos:height="match_content"
ohos:left_margin="20vp"
ohos:top_margin="20vp"
ohos:text_color="black"
ohos:width="match_content"/>
<Text
ohos:id="$+id:product_price"
ohos:height="match_content"
ohos:top_margin="20vp"
ohos:text_size="15vp"
ohos:width="match_content"/>
</DirectionalLayout>
<DirectionalLayout
ohos:height="match_content"
ohos:width="match_content"
ohos:orientation="horizontal">
<Text
ohos:text="产品类型:"
ohos:text_size="15vp"
ohos:height="match_content"
ohos:left_margin="20vp"
ohos:top_margin="20vp"
ohos:text_color="black"
ohos:width="match_content"/>
<Text
ohos:id="$+id:product_type"
ohos:height="match_content"
ohos:hint="电脑"
ohos:top_margin="20vp"
ohos:hint_color="red"
ohos:text_size="15vp"
ohos:width="match_content"/>
</DirectionalLayout>
<Component
ohos:height="1vp"
ohos:width="match_parent"
ohos:background_element="gray"
/>
</DirectionalLayout>
4、配置config.json
工程需要访问外网的环境,所以需要配置以下两项:
1、配置deviceConfig,访问的url是以http开始
"deviceConfig": {
"default": {
"network": {
"cleartextTraffic": true
}
}
},
2、配置reqPermissions以用来访问外网
"reqPermissions": [
{
"reason": "",
"name": "ohos.permission.INTERNET"
}
],
5、配置项目级别的build.gradle文件
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
testImplementation 'junit:junit:4.13'
compile 'com.google.code.gson:gson:2.6.2'
implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.1.0'
ohosTestImplementation 'com.huawei.ohos.testkit:runner:1.0.0.200'
}
6、创建一个Product实体类
注意的是该类的属性一定要和解析的Json格式要对应,主要是使用GsonFormatPlus这个插件来完成
package com.qf.listcontainerjson.bean;
import java.util.List;
public class Product {
private List<ProductsBean> products;
public List<ProductsBean> getProducts() {
return products;
}
public void setProducts(List<ProductsBean> products) {
this.products = products;
}
public static class ProductsBean {
private int pid;
private String pname;
private int price;
private String category_name;
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getCategory_name() {
return category_name;
}
public void setCategory_name(String category_name) {
this.category_name = category_name;
}
@Override
public String toString() {
return "ProductsBean{" +
"pid=" + pid +
", pname='" + pname + '\'' +
", price=" + price +
", category_name='" + category_name + '\'' +
'}';
}
}
}
7、封装一个OKHttp工具类
封装一个基于Okhttp的工具类,主要使用单例模式,异步的Get请求来获取Json数据
package com.qf.listcontainerjson.http;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class HTTPManager {
private static HTTPManager instance;
private OkHttpClient okHttpClient;
private HTTPManager(){
okHttpClient = new OkHttpClient().newBuilder().build();
}
public static HTTPManager getInstance(){
if (instance==null){
synchronized (HTTPManager.class){
if (instance==null){
instance = new HTTPManager();
}
}
}
return instance;
}
public void _getasync(String url, Callback callback){
Request request = new Request.Builder().url(url).build();
Call call = okHttpClient.newCall(request);
call.enqueue(callback);
}
}
8、声明一个产品适配器ProductAdapter
package com.qf.listcontainerjson.adapter;
import com.qf.listcontainerjson.ResourceTable;
import com.qf.listcontainerjson.bean.Product;
import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.components.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import java.util.List;
public class ProductAdapter extends BaseItemProvider {
private static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP,0x00201,"ProductAdapter");
private List<Product.ProductsBean> list;
private AbilitySlice slice;
public ProductAdapter(List<Product.ProductsBean> list,AbilitySlice slice){
this.list = list;
this.slice = slice;
}
@Override
public int getCount() {
return list==null?0:list.size();
}
@Override
public Object getItem(int position) {
if (list!=null&&position>=0&&position<list.size()){
return list.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
ViewHolder viewHolder = null;
if (component==null){
component = LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_product_item,null,false);
viewHolder = new ViewHolder();
viewHolder.p_name = (Text)component.findComponentById(ResourceTable.Id_product_name);
viewHolder.p_price=(Text)component.findComponentById(ResourceTable.Id_product_price);
viewHolder.p_type = (Text)component.findComponentById(ResourceTable.Id_product_type);
component.setTag(viewHolder);
}else {
viewHolder = (ViewHolder)component.getTag();
}
if (viewHolder!=null){
viewHolder.p_name.setText(list.get(i).getPname());
viewHolder.p_price.setText(String.valueOf(list.get(i).getPrice()));
viewHolder.p_type.setText(list.get(i).getCategory_name());
}
return component;
}
static class ViewHolder{
Text p_name;
Text p_type;
Text p_price;
}
}
9、在MainAbilitySlice中加载适配器
package com.qf.listcontainerjson.slice;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.qf.listcontainerjson.ResourceTable;
import com.qf.listcontainerjson.adapter.ProductAdapter;
import com.qf.listcontainerjson.bean.Product;
import com.qf.listcontainerjson.http.HTTPManager;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.ListContainer;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.List;
public class MainAbilitySlice extends AbilitySlice {
private static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP,0x00201,"MainAbilitySlice");
private ListContainer listContainer;
private String url = "http://sudojava.free.idcfengye.com/products";
private ProductAdapter adapter;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
listContainer = (ListContainer)findComponentById(ResourceTable.Id_product_list);
initView();
}
private void initView(){
HTTPManager.getInstance()._getasync(url, new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
List<Product.ProductsBean> list = new Gson().fromJson(response.body().string(),new TypeToken<List<Product.ProductsBean>>(){}.getType());
HiLog.info(LOG_LABEL,"--->>"+list);
adapter = new ProductAdapter(list,MainAbilitySlice.this);
getUITaskDispatcher().asyncDispatch(new Runnable() {
@Override
public void run() {
listContainer.setItemProvider(adapter);
adapter.notifyDataChanged();
}
});
}
});
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
4.5、ListContainer加载图文混排
准备一段图文混排的Json数据,数据格式如下:
{
"vlist":[
{
"publishTime":1439567432000,
"vpic":"http://pic9.iqiyipic.com/image/20190905/96/f9/v_109343020_m_601_m3.jpg",
"shortTitle":"航海王 第1集",
"vt":"我是路飞! 将要成为海贼王的男人"
},
{
"publishTime":1439567432000,
"vpic":"http://pic8.iqiyipic.com/image/20190905/5f/27/v_109343021_m_601_m4.jpg",
"shortTitle":"航海王 第2集",
"vt":"大剑客现身!海贼猎人罗罗诺亚·卓洛"
},
{
"publishTime":1439567432000,
"vpic":"http://pic3.iqiyipic.com/image/20150803/d9/3b/v_109343022_m_601.jpg",
"shortTitle":"航海王 第3集",
"vt":"蒙卡 vs 路飞!神秘的美少女是谁?"
},
{
"publishTime":1439567435000,
"vpic":"http://pic4.iqiyipic.com/image/20150803/91/03/v_109343023_m_601.jpg",
"shortTitle":"航海王 第4集",
"vt":"路飞的过去!红发香克斯登场"
},
{
"publishTime":1439567433000,
"vpic":"http://pic0.iqiyipic.com/image/20150803/b7/aa/v_109343025_m_601.jpg",
"shortTitle":"航海王 第5集",
"vt":"恐怖!神秘的力量 海贼小丑巴基船长"
},
{
"publishTime":1439567432000,
"vpic":"http://pic2.iqiyipic.com/image/20150803/fa/a1/v_109343027_m_601.jpg",
"shortTitle":"航海王 第6集",
"vt":"绝体绝命!驯兽师摩奇VS路飞"
},
{
"publishTime":1439567432000,
"vpic":"http://pic3.iqiyipic.com/image/20150803/a0/99/v_109343028_m_601.jpg",
"shortTitle":"航海王 第7集",
"vt":"壮烈决斗!剑豪卓洛VS杂技师卡巴吉"
},
{
"publishTime":1439567432000,
"vpic":"http://pic2.iqiyipic.com/image/20150804/05/a7/v_109343029_m_601_m1.jpg",
"shortTitle":"航海王 第8集",
"vt":"胜利者是谁?恶魔果实的能力对决!"
},
{
"publishTime":1439567433000,
"vpic":"http://pic6.iqiyipic.com/image/20150803/b7/ee/v_109343030_m_601.jpg",
"shortTitle":"航海王 第9集",
"vt":"正义的骗子?船长乌索普"
},
{
"publishTime":1439567432000,
"vpic":"http://pic8.iqiyipic.com/image/20150804/e6/e9/v_109343032_m_601_m1.jpg",
"shortTitle":"航海王 第10集",
"vt":"史上最强的怪人!催眠师赞高"
},
{
"publishTime":1439567435000,
"vpic":"http://pic5.iqiyipic.com/image/20150803/e9/d9/v_109343035_m_601.jpg",
"shortTitle":"航海王 第11集",
"vt":"阴谋暴露! 海贼管家克洛船长"
},
{
"publishTime":1439567435000,
"vpic":"http://pic6.iqiyipic.com/image/20150803/7d/f1/v_109343036_m_601.jpg",
"shortTitle":"航海王 第12集",
"vt":"激战!与黑猫海贼团坡道的大攻防!"
},
{
"publishTime":1439567436000,
"vpic":"http://pic8.iqiyipic.com/image/20150803/2e/f6/v_109343038_m_601.jpg",
"shortTitle":"航海王 第13集",
"vt":"恐怖的二人组!猫人兄弟VS卓洛"
},
{
"publishTime":1439567435000,
"vpic":"http://pic7.iqiyipic.com/image/20150804/91/6b/v_109343039_m_601_m1.jpg",
"shortTitle":"航海王 第14集",
"vt":"路飞复活!可雅小姐的拼死抵抗"
},
{
"publishTime":1439567435000,
"vpic":"http://pic4.iqiyipic.com/image/20150803/6b/38/v_109343041_m_601.jpg",
"shortTitle":"航海王 第15集",
"vt":"把克洛打倒!男子汉乌索普悲痛的决定!"
}]
}
将该json数据保存到一个movie.json文件中,放到指定的目录下,这里我是放到E盘的json文件夹中。
使用json-server启动,生成restful风格的数据。启动命令如下:
E:\json>json-server --watch --host 127.0.0.1 --port 8080 movie.json
\{^_^}/ hi!
Loading movie.json
Done
Resources
http://127.0.0.1:8080/vlist
Home
http://127.0.0.1:8080
Type s + enter at any time to create a snapshot of the database
Watching...
启动ngrok,将内网的地址映射到外网,启动信息如下:
nnel Status online
Version 2.1/2.1 http://sudojava.free.idcfengye.com -> 127.0.0.1:8080
配置config.json文件
工程需要访问外网的环境,所以需要配置以下两项:
- 配置deviceConfig,访问的url是以http开始
"deviceConfig": {
"default": {
"network": {
"cleartextTraffic": true
}
}
},
- 配置module 模块下的reqPermissions以用来访问外网
"reqPermissions": [
{
"reason": "",
"name": "ohos.permission.INTERNET"
}
],
- 配置项目级别的build.gradle文件
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
testImplementation 'junit:junit:4.13'
ohosTestImplementation 'com.huawei.ohos.testkit:runner:1.0.0.200'
compile 'com.google.code.gson:gson:2.6.2'
implementation 'io.openharmony.tpc.thirdlib:picasso:1.0.4'
implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.1.0'
}
1、创建两个工程对应的布局文件,ability_main.xml和movie_item.xml
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<ListContainer
ohos:id="$+id:movie_list"
ohos:height="match_parent"
ohos:width="match_parent"/>
</DirectionalLayout>
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_content"
ohos:width="match_parent"
ohos:orientation="vertical">
<Image
ohos:id="$+id:vpic"
ohos:top_margin="10vp"
ohos:left_margin="20vp"
ohos:height="match_content"
ohos:image_src="$media:icon"
ohos:width="match_content"/>
<DirectionalLayout
ohos:height="match_content"
ohos:width="match_content"
ohos:orientation="horizontal">
<Text
ohos:text="电影标题:"
ohos:text_size="15vp"
ohos:height="match_content"
ohos:left_margin="20vp"
ohos:top_margin="20vp"
ohos:text_color="black"
ohos:width="match_content"/>
<Text
ohos:id="$+id:shortTitle"
ohos:height="match_content"
ohos:hint="香蕉"
ohos:top_margin="20vp"
ohos:hint_color="red"
ohos:text_size="15vp"
ohos:width="match_content"/>
</DirectionalLayout>
<DirectionalLayout
ohos:height="match_content"
ohos:width="match_content"
ohos:orientation="horizontal">
<Text
ohos:text="发布时间:"
ohos:text_size="15vp"
ohos:height="match_content"
ohos:left_margin="20vp"
ohos:top_margin="20vp"
ohos:text_color="black"
ohos:width="match_content"/>
<Text
ohos:id="$+id:publishTime"
ohos:height="match_content"
ohos:top_margin="20vp"
ohos:text_size="15vp"
ohos:width="match_content"/>
</DirectionalLayout>
<DirectionalLayout
ohos:height="match_content"
ohos:width="match_content"
ohos:orientation="horizontal">
<Text
ohos:text="电影简介:"
ohos:text_size="15vp"
ohos:height="match_content"
ohos:left_margin="20vp"
ohos:top_margin="20vp"
ohos:text_color="black"
ohos:width="match_content"/>
<Text
ohos:id="$+id:vt"
ohos:height="match_content"
ohos:hint="简介"
ohos:top_margin="20vp"
ohos:hint_color="red"
ohos:text_size="15vp"
ohos:width="match_content"/>
</DirectionalLayout>
<Component
ohos:height="1vp"
ohos:width="match_parent"
ohos:background_element="gray"
/>
</DirectionalLayout>
2、创建一个json对应的实体类
package com.qf.listmovie.bean;
import java.util.List;
public class Movie {
private List<VlistBean> vlist;
public List<VlistBean> getVlist() {
return vlist;
}
public void setVlist(List<VlistBean> vlist) {
this.vlist = vlist;
}
public static class VlistBean {
private long publishTime;
private String vpic;
private String shortTitle;
private String vt;
public long getPublishTime() {
return publishTime;
}
public void setPublishTime(long publishTime) {
this.publishTime = publishTime;
}
public String getVpic() {
return vpic;
}
public void setVpic(String vpic) {
this.vpic = vpic;
}
public String getShortTitle() {
return shortTitle;
}
public void setShortTitle(String shortTitle) {
this.shortTitle = shortTitle;
}
public String getVt() {
return vt;
}
public void setVt(String vt) {
this.vt = vt;
}
}
}
3、编写一个HTTP访问工具类和日期转换类
package com.qf.listmovie.http;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class HTTPManager {
private static HTTPManager instance;
private OkHttpClient okHttpClient;
private HTTPManager(){
okHttpClient = new OkHttpClient().newBuilder().build();
}
public static HTTPManager getInstance(){
if (instance==null){
synchronized (HTTPManager.class){
if (instance==null){
instance = new HTTPManager();
}
}
}
return instance;
}
public void _getasync(String url, Callback callback){
Request request = new Request.Builder().url(url).build();
Call call = okHttpClient.newCall(request);
call.enqueue(callback);
}
}
日期转换工具类
package com.qf.listmovie.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtils {
public static String dateFormat(Long l){
Date date = new Date();
date.setTime(l);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
return format.format(date);
}
}
4、编写ListContainer对应的适配器类
package com.qf.listmovie.adapter;
import com.qf.listmovie.ResourceTable;
import com.qf.listmovie.bean.Movie;
import com.qf.listmovie.utils.DateUtils;
import com.squareup.picasso.Picasso;
import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.components.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import java.util.ArrayList;
import java.util.List;
public class MoiveAdapter extends BaseItemProvider {
private static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP,0x00201,"MoiveAdapter");
private List<Movie.VlistBean> list;
private AbilitySlice slice;
public MoiveAdapter(List<Movie.VlistBean> list,AbilitySlice slice){
this.list = list;
this.slice = slice;
}
public int getCount() {
return list==null?0:list.size();
}
@Override
public Object getItem(int position) {
if (list!=null&&position>=0&&position<list.size()){
return list.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
ViewHolder viewHolder = null;
if (component==null){
component = LayoutScatter.getInstance(slice)
.parse(ResourceTable.Layout_movie_item,null,false);
viewHolder = new ViewHolder();
viewHolder.m_publishTime = (Text)component.findComponentById(ResourceTable.Id_publishTime);
viewHolder.m_shortTitle=(Text)component.findComponentById(ResourceTable.Id_shortTitle);
viewHolder.m_vt = (Text)component.findComponentById(ResourceTable.Id_vt);
viewHolder.m_vpic = (Image)component.findComponentById(ResourceTable.Id_vpic);
component.setTag(viewHolder);
}else {
viewHolder = (ViewHolder)component.getTag();
}
if (viewHolder!=null){
viewHolder.m_publishTime.setText(DateUtils.dateFormat(list.get(i).getPublishTime()));
viewHolder.m_shortTitle.setText(list.get(i).getShortTitle());
viewHolder.m_vt.setText(list.get(i).getVt());
Picasso.get().load(list.get(i).getVpic())
.placeholder(ResourceTable.Media_icon)
.resize(150,150)
.into(viewHolder.m_vpic);
}
return component;
}
static class ViewHolder{
Text m_publishTime;
Text m_shortTitle;
Text m_vt;
Image m_vpic;
}
}
5、在MainAbilitySlice中加载数据
package com.qf.listmovie.slice;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.qf.listmovie.ResourceTable;
import com.qf.listmovie.adapter.MoiveAdapter;
import com.qf.listmovie.bean.Movie;
import com.qf.listmovie.http.HTTPManager;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.ListContainer;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.List;
public class MainAbilitySlice extends AbilitySlice {
private static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP,0x00201,"MainAbilitySlice");
private String url = "http://sudojava.free.idcfengye.com/vlist";
private ListContainer listContainer;
private MoiveAdapter adapter;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
listContainer = (ListContainer)findComponentById(ResourceTable.Id_movie_list);
initView();
}
private void initView() {
HTTPManager.getInstance()._getasync(url, new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
List<Movie.VlistBean> list = new Gson()
.fromJson(response.body().string(),new TypeToken<List<Movie.VlistBean>>(){}.getType());
HiLog.info(LOG_LABEL,"--->>"+list);
adapter = new MoiveAdapter(list,MainAbilitySlice.this);
getUITaskDispatcher().asyncDispatch(new Runnable() {
@Override
public void run() {
listContainer.setItemProvider(adapter);
adapter.notifyDataChanged();
}
});
}
});
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
更多推荐
所有评论(0)