MVP+OKhttp,拦截器+XRecyclerView+ImageLoader(Glide)

1 . 效果图

 

 MVP+OKhttp,拦截器+XRecyclerView+ImageLoader(Glide)_第1张图片

 

(图1)    

 MVP+OKhttp,拦截器+XRecyclerView+ImageLoader(Glide)_第2张图片                           

  (图2)

 

一、技术选型:

1. 项目框架:MVP;注意:避免内存泄漏;

2. 图片加载: Universal-Image-Loader或Glide图片加载框架

3.网络加载框架:OkHttp

4. 自定义应用拦截器,封装公共请求参数(注意:必须通过拦截器封装公共请求参数,否则无法请求数据

公共请求参数,在我们项目研发过程中,作用非常大。封装公共请求承参数之后,那么所有的接口都会默认携带这些公共参数,达到复用的效果。

公共请求参数:source=android

参数名称:source

参数值:android

类型:String

是否必传:是

5. 数据展示使用RecylerView

二、业务逻辑需求:

1. 搜索框输入关键字(笔记本、手机),其他关键词没有数据,点击搜索实现如图效果;

2. 1是列表布局,图2是网格布局;

3. 通过右上角按钮点击切换列表布局和网格布局,按钮随着切换;

4. 实现下拉刷新展示第一页数据、上拉加载更多实现分页功能。

三、接口:

http://120.27.23.105/product/searchProducts

keywords=笔记本&page=1

参数说明:

keywords 关键字字段 String类型 必传

page  页码数  String类型  必传

公共参数:source 来源字段 String类型 (通过自定义拦截器封装


1.  导包:gson包,ImageLoader(Glide)包,


2. 添加依赖:

(1)butterknife自动生成控件id和点击事件:

     compile 'com.jakewharton:butterknife:7.0.0'

(2)okhttp依赖:
     compile 'com.squareup.okhttp3:okhttp:3.9.0'
(3)xRecyclerView依赖:
     compile 'com.jcodecraeer:xrecyclerview:1.3.2'

一 . 首先编写OKhttp的封装类

(1)OkHttpUtils

package com.okhttp;
import android.os.Handler;
import java.util.concurrent.TimeUnit;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;

public class OkHttpUtils {
    private Handler handler=new Handler();
    public Handler getHandler(){
        return handler;
    }
    //单例
    private static OkHttpUtils okHttpUtils = null;
    private OkHttpUtils(){};
    public static OkHttpUtils getInstance(){
        if(okHttpUtils == null){            //不适用拦截器时,可以把if判断内的代码去除
            okHttpUtils = new OkHttpUtils();
            client = new OkHttpClient.Builder()
                    .readTimeout(20, TimeUnit.SECONDS)
                    .writeTimeout(20,TimeUnit.SECONDS)
                    .connectTimeout(20, TimeUnit.SECONDS)
                    .addInterceptor(new LoggingInterceptor())
                    .build();
        }
        return okHttpUtils;
    }

    private static OkHttpClient client;
    private void initOkHttpClient(){
        if (client==null){
            client=new OkHttpClient.Builder().build();
        }
    }
    //公用的get请求方法  完成的功能不确定
    public void doGet(String url, Callback callback){
        initOkHttpClient();
        Request request=new Request.Builder().url(url).build();
        client.newCall(request).enqueue(callback);
    }
}
(2) OkHttp3Utils

package com.okhttp;

import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 1. 类的用途
 * 2. @author 
 * 
 */

public class OkHttp3Utils {

    private static OkHttpClient okHttpClient = null;

    public OkHttp3Utils() {
    }

    private static OkHttpClient getOkHttpClient() {
        synchronized (OkHttp3Utils.class) {
            if (okHttpClient == null) {
                okHttpClient = new OkHttpClient();
            }
        }
        return okHttpClient;
    }

    //上传文件
    public static void loadFile(String url, File file,String fileName){
        OkHttpClient okHttpClient = getOkHttpClient();
        //设置文件类型
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/octet-stream"),file);
        //设置请求体
        RequestBody body = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("image",fileName,requestBody)
                .build();
        //请求方式
        Request request = new Request.Builder().url(url).post(body).build();

        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.i("成功","成功");
            }
        });
    }

    /**
     * 1.接口地址
     * 2.接口回调
     */
    public static void doGet(String url,Callback callback){
        OkHttpClient okHttpClient = getOkHttpClient();
        Request request = new Request.Builder().url(url).build();
        okHttpClient.newCall(request).enqueue(callback);
    }

    /**
     * 1.地址
     * 2.接口回调
     * 3.请求体
     */

    public static void doPost(String url, Map map,Callback callback){
        OkHttpClient okHttpClient = getOkHttpClient();
        FormBody.Builder builder = new FormBody.Builder();
        //遍历map集合   设置请求体
        for (String mapKey : map.keySet()){
           builder.add(mapKey,map.get(mapKey));
        }
        //设置请求方式
        Request request = new Request.Builder().url(url).post(builder.build()).build();
        //执行请求方式    接口回调
        okHttpClient.newCall(request).enqueue(callback);
    }

    /**
     *1.下载地址
     */
    public static void doDown(String url,Callback callback){
        OkHttpClient okHttpClient = getOkHttpClient();
        Request build = new Request.Builder().url(url).build();

        okHttpClient.newCall(build).enqueue(callback);
    }
}
(3) OnUiCallback

package com.okhttp;

import android.os.Handler;

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

public abstract class OnUiCallback implements Callback {
    private Handler handler=OkHttpUtils.getInstance().getHandler();
    public abstract void onFailed(Call call,IOException e);
    public abstract void onSuccess(String result);


    @Override
    public void onFailure(final Call call, final IOException e) {
        //该方法就是把  线程post到handler所在的线程
        handler.post(new Runnable() {
            @Override
            public void run() {
//                e.getMessage()
                onFailed(call,e);
            }
        });
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        final String result=response.body().string();
        handler.post(new Runnable() {
            @Override
            public void run() {
                onSuccess(result);
            }
        });
    }
}
(4) LoggingInterceptor(拦截器类)

package com.okhttp;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
 * 拦截器类
 */
//自定义应用拦截器
public class LoggingInterceptor implements Interceptor {
    @Override public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        long t1 = System.nanoTime();
//    logger.info(String.format("Sending request %s on %s%n%s",
//        request.url(), chain.connection(), request.headers()));

        Response response = chain.proceed(request);

        long t2 = System.nanoTime();
//    logger.info(String.format("Received response for %s in %.1fms%n%s",
//        response.request().url(), (t2 - t1) / 1e6d, response.headers()));

        System.out.println("t2 = " + (t2-t1));
        return response;
    }
}
. model层
import com.bwie.duhongwang.okhttp.OkHttp3Utils;
import okhttp3.Callback;
/**
 * model层,查询数据的接口实现类
 */
public class MyDataModel {
    //传三个参数(公共请求参数) 一个是分页加载时用到的 page 还有  输入框内搜索的值,还有callback 用来在presenter内拿出bean
    public void getData(String keywords, String page, Callback callback ){
        OkHttp3Utils.doGet("http://120.27.23.105/product/searchProducts?keywords="+keywords+"&page="+page+"&source=android",callback);
    }
}
model层实现的接口

//model层,数据的查询接口
public interface SearchModel {
        public void getData(String keywords, String page, okhttp3.Callback callback);
}

三. view层

import com.bwie.duhongwang.bean.ProductsBean;
/**
 * view层,UI界面的搭建
 */
public interface DataView {
    public void showView(ProductsBean productsBean);   //成功获取数据
}
 
  
四. presenter层
import android.content.Context;
import android.util.Log;
import com.bwie.duhongwang.bean.ProductsBean;
import com.bwie.duhongwang.model.MyDataModel;
import com.bwie.duhongwang.okhttp.OnUiCallback;
import com.bwie.duhongwang.view.DataView;
import com.google.gson.Gson;
import java.io.IOException;
import okhttp3.Call;
/**
 * presenter层,进行model和view层之间数据的交互
 */
public class DataPresenter {
    Context context;
    private DataView dataView;
    private MyDataModel dataModel;
    //构造方法中声明view层,初始化model层数据,将 mvp三层关联
    public DataPresenter(Context context, DataView dataView) {
        this.context = context;
        this.dataView = dataView;
        dataModel = new MyDataModel();
    }

    //调用model层接口,上拉加载下拉刷新
    public void getData(String keyword,String page){
        dataModel.getData(keyword, page, new OnUiCallback() {
            @Override
            public void onFailed(Call call, IOException e) {
                //数据获取//失败方法
            }

            @Override
            public void onSuccess(String result) {
                //获取数据成功时将放回的json 变成bean
                Log.i("返回数据", "结果: "+result.toString());
                ProductsBean bean = new Gson().fromJson(result, ProductsBean.class);
                dataView.showView(bean);
            }
        });
    }

    //用来防止内存溢出
    public void destory(){
        this.dataView = null;
    }
}

五. imageloader工具类及其全局初始化配置

(1)全局初始化配置类:

package com.bwie.secondweek.util;

import android.app.Application;
//全局初始化Application类
public class BaseApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        //配置imageLoader
        ImageLoaderUtil.init(this);
    }
}

(2)imageloader工具类:

package com.bwie.secondweek.util;
import android.content.Context;
import android.graphics.Bitmap;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
import com.nostra13.universalimageloader.cache.disc.naming.HashCodeFileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.decode.BaseImageDecoder;
import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;
import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import com.nostra13.universalimageloader.utils.StorageUtils;

import java.io.File;
public class ImageLoaderUtil {
    /**
     * 初始化imageLoader
     * @param context
     */
    public static void init(Context context) {
        //1.获取配置config对象
        File cacheDir = StorageUtils.getCacheDirectory(context);  //缓存文件夹路径

        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)

                .threadPoolSize(3) // default  线程池内加载的数量
                .threadPriority(Thread.NORM_PRIORITY - 2) // default 设置当前线程的优先级
                .tasksProcessingOrder(QueueProcessingType.FIFO) // default
                .denyCacheImageMultipleSizesInMemory()
                .memoryCache(new LruMemoryCache(2 * 1024 * 1024)) //可以通过自己的内存缓存实现
                .memoryCacheSize(2 * 1024 * 1024)  // 内存缓存的最大值
                .memoryCacheSizePercentage(13) // default
                .diskCache(new UnlimitedDiscCache(cacheDir)) // default 可以自定义缓存路径
                .diskCacheSize(50 * 1024 * 1024) // 50 Mb sd卡(本地)缓存的最大值
                .diskCacheFileCount(100)  // 可以缓存的文件数量
                // default为使用HASHCODE对UIL进行加密命名, 还可以用MD5(new Md5FileNameGenerator())加密
                .diskCacheFileNameGenerator(new HashCodeFileNameGenerator())
                .imageDownloader(new BaseImageDownloader(context)) // default
                .imageDecoder(new BaseImageDecoder(true)) // default
                .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default
                .writeDebugLogs() // 打印debug log
                .build(); //开始构建


        //2.初始化配置...ImageLoader.getInstance()图片加载器的对象,单例模式
        ImageLoader.getInstance().init(config);
    }

    /**
     * imageLoader加载图片的默认选项
     * @return
     */
    public static DisplayImageOptions getDefaultOption(){

        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.mipmap.ic_launcher) // 设置图片下载期间显示的默认图片
                .showImageForEmptyUri(R.mipmap.ic_launcher) // 设置图片Uri为空或是错误的时候显示的图片
                .showImageOnFail(R.mipmap.ic_launcher) // 设置图片加载或解码过程中发生错误显示的图片
                .resetViewBeforeLoading(true)  // default 设置图片在加载前是否重置、复位
                .delayBeforeLoading(1000)  // 下载前的延迟时间
                .cacheInMemory(true) // default  设置下载的图片是否缓存在内存中
                .cacheOnDisk(true) // default  设置下载的图片是否缓存在SD卡中

                .considerExifParams(true) // default
                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 设置图片以如何的编码方式显示
                .bitmapConfig(Bitmap.Config.RGB_565) // default 设置图片的解码类型

                .displayer(new SimpleBitmapDisplayer()) // default  还可以设置圆角图片new RoundedBitmapDisplayer(20)

                .build();

        return options;
    }

    /**
     * imageLoader加载圆角图片....指定圆角的大小
     * @return
     */
    public static DisplayImageOptions getRoundedOption(int corner){

        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.mipmap.ic_launcher) // 设置图片下载期间显示的图片
                .showImageForEmptyUri(R.mipmap.ic_launcher) // 设置图片Uri为空或是错误的时候显示的图片
                .showImageOnFail(R.mipmap.ic_launcher) // 设置图片加载或解码过程中发生错误显示的图片
                .resetViewBeforeLoading(true)  // default 设置图片在加载前是否重置、复位
                .delayBeforeLoading(1000)  // 下载前的延迟时间
                .cacheInMemory(true) // default  设置下载的图片是否缓存在内存中
                .cacheOnDisk(true) // default  设置下载的图片是否缓存在SD卡中

                .considerExifParams(true) // default
                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 设置图片以如何的编码方式显示
                .bitmapConfig(Bitmap.Config.RGB_565) // default 设置图片的解码类型
                .displayer(new RoundedBitmapDisplayer(corner)) // default  还可以设置圆角图片new RoundedBitmapDisplayer(20)

                .build();

        return options;
    }

}


六. 数据接口封装的bean类(根据自己需要定义)
七. 主功能代码;MainActivity.java

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import com.bwie.duhongwang.adapter.MyAdapter;
import com.bwie.duhongwang.bean.ProductsBean;
import com.bwie.duhongwang.presenter.DataPresenter;
import com.bwie.duhongwang.view.DataView;
import com.jcodecraeer.xrecyclerview.XRecyclerView;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;

//列表页
public class MainActivity extends AppCompatActivity implements DataView {
    @Bind(R.id.grid_icon)
    ImageView gridIcon;
    @Bind(R.id.find)
    Button find;
    @Bind(R.id.xRecyclerView)
    XRecyclerView xRecyclerView;
    @Bind(R.id.editWords)
    EditText editWords;
    private int num = 1;    //判断变量改变布局
    private int page = 1;   //初始化页数数据
    private MyAdapter adapter;
    private Handler handler = new Handler();
    private DataPresenter dataPresenter = new DataPresenter(this,this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        //默认显示一页数据
        dataPresenter.getData("笔记本","1");
    }

    //view 层 的方法 用来更新ui
    @Override
    public void showView(ProductsBean productsBean) {

        //设置线性布局管理器,加载数据
        if (num % 2 == 1) {
            //设置线性布局管理器,加载数据
            LinearLayoutManager layoutManager = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false);
            xRecyclerView.setLayoutManager(layoutManager);
            gridIcon.setBackgroundResource(R.drawable.lv_icon);
        }
        //设置布局适配器,,,线性布局管理器,加载数据
        adapter = new MyAdapter(MainActivity.this,  productsBean);
        xRecyclerView.setAdapter(adapter);

        //XRecyclerview的上拉下拉方法
        xRecyclerView.setLoadingListener(new XRecyclerView.LoadingListener() {
            @Override
            public void onRefresh() {
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //在子线程内上拉刷新数据
                        dataPresenter.getData(editWords.getText().toString(),"1");
                        adapter.notifyDataSetChanged();
                        xRecyclerView.refreshComplete();
                    }
                },800);
            }

            @Override
            public void onLoadMore() {
                //在子线程内下拉加载数据
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        page++;
                        dataPresenter.getData(editWords.getText().toString(),page+"");
                        adapter.notifyDataSetChanged();
                        xRecyclerView.loadMoreComplete();
                    }
                },800);
            }
        });
    }

    @OnClick({R.id.grid_icon, R.id.find})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.grid_icon:
                //根据num变量是奇数还是偶数来判断加载哪种布局,并返回对应布局的图片
                num++;
                if (num % 2 == 0) {
                    //设置网格布局管理器,加载数据
                    GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
                    xRecyclerView.setLayoutManager(layoutManager);
                    gridIcon.setBackgroundResource(R.drawable.grid_icon);
                }
                if (num % 2 == 1) {
                    //设置线性布局管理器,加载数据
                    LinearLayoutManager layoutManager = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false);
                    xRecyclerView.setLayoutManager(layoutManager);
                    gridIcon.setBackgroundResource(R.drawable.lv_icon);
                }
                break;
            case R.id.find:
                //点击搜索按钮时触发presenter的获取数据方法
                dataPresenter.getData(editWords.getText().toString(),"1");
                break;
            default:
                break;
        }
    }

    //实现presenter内部的防止内存溢出方法
    @Override
    protected void onDestroy() {
        super.onDestroy();
        dataPresenter.destory();
    }
}

八. 适配器类

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bwie.duhongwang.R;
import com.bwie.duhongwang.bean.ProductsBean;
import com.bwie.duhongwang.util.ImageLoaderUtil;
import com.nostra13.universalimageloader.core.ImageLoader;

import butterknife.Bind;
import butterknife.ButterKnife;

//自定义适配器
public class MyAdapter extends RecyclerView.Adapter {
    private Context context;
    private ProductsBean productsBean;

    public MyAdapter(Context context, ProductsBean productsBean) {
        this.context = context;
        this.productsBean = productsBean;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.item, null);
        return new ItemViewHolder(view);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        //设置条目信息
        ItemViewHolder viewHolder = (ItemViewHolder) holder;
        viewHolder.title.setText("标题: "+productsBean.getData().get(position).getTitle() );
        viewHolder.price.setText("价格: "+productsBean.getData().get(position).getPrice() );
        String images = productsBean.getData().get(position).getImages();
        String[] split = images.split("\\|");

        //使用Glide加载图片容易闪烁,错位,效果不如imageloader好
        //Glide.with(context).load(split[0]).into(viewHolder.image);
        ImageLoader.getInstance().displayImage(split[0], viewHolder.image, ImageLoaderUtil.getDefaultOption());
    }

    @Override
    public int getItemCount() {
        return productsBean.getData() == null ? 0 : productsBean.getData().size();
    }

    static class ItemViewHolder extends RecyclerView.ViewHolder {
        @Bind(R.id.image)
        ImageView image;
        @Bind(R.id.title)
        TextView title;
        @Bind(R.id.price)
        TextView price;
        public ItemViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}
. 页面布局
1. activity_main.xml
xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:id="@+id/relative01">
        <TextView
            android:layout_centerInParent="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="21sp"
            android:text="搜索商品" />

        <ImageView
            android:background="@drawable/lv_icon"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="10dp"
            android:layout_height="35dp"
            android:layout_width="35dp"
            android:id="@+id/grid_icon" />
    RelativeLayout>

    <View
        android:id="@+id/view01"
        android:background="#000"
        android:layout_height="1dp"
        android:visibility="visible"
        android:layout_width="match_parent"
        android:layout_below="@+id/relative01">View>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_below="@+id/view01"
        android:layout_height="50dp"
        android:id="@+id/relative02">
        <EditText
            android:layout_centerVertical="true"
            android:layout_height="wrap_content"
            android:layout_marginLeft="38dp"
            android:layout_width="218dp"
            android:id="@+id/editWords"
            android:hint="请输入关键词"
            android:textSize="21sp" />

        <Button
            android:text="搜索"
            android:id="@+id/find"
            android:layout_marginRight="38dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"/>
    RelativeLayout>

    <View
        android:id="@+id/view02"
        android:background="#000"
        android:visibility="visible"
        android:layout_height="1dp"
        android:layout_width="match_parent"
        android:layout_below="@+id/relative02">View>

    <com.jcodecraeer.xrecyclerview.XRecyclerView
        android:id="@+id/xRecyclerView"
        android:layout_below="@+id/view02"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >com.jcodecraeer.xrecyclerview.XRecyclerView>
RelativeLayout>
2. item.xml

xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:padding="5dp"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@mipmap/ic_launcher"/>

    <LinearLayout
        android:layout_height="100dp"
        android:orientation="vertical"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"  >
        <TextView
            android:id="@+id/title"
            android:layout_weight="1"
            android:layout_height="0dp"
            android:layout_width="wrap_content"/>
        <TextView
            android:id="@+id/price"
            android:layout_weight="1"
            android:layout_height="0dp"
            android:layout_width="wrap_content"/>
    LinearLayout>
LinearLayout>

十. 清单文件AndrodiManifest.xml

1. 配置ImageLoader的全局初始化类(name属性);

2. 添加请求网络数据的权限(INTENT)。

你可能感兴趣的:(工程搭建)