Android實踐:xUtils3探究

一、xUtils3簡介
xUtils是一個android使用工具框架,包含了如下幾大功能:
  註解定義:提供了佈局,視圖和事件等註解,能夠簡化相關的Android代碼;
  網絡請求:支持GET、PUT、DELETE和PUT等請求方式,封裝了異步Task,支持FIFO和FILO優先級線程池,提供了同步異步請求,支持https、cookie和硬盤緩存等;
  圖片綁定:封裝了內存和硬盤緩存,優化了Bitmap加載過程,處理了ViewHolder產生的圖片錯亂問題,支持https等;
  數據封裝:封裝了相關概念,直接將JavaBean映射成對應的表,封裝sql語句的select、where和insert等語句操作等;
具體的實現,大家可以到github(https://github.com/wyouflf/xUtils3)上下載相關源碼進行學習。下面我們就xUtils3的基本使用,結合一個圖片列表的Demo跟大家進行介紹。該項目的源碼使用了MVP和Https相關知識,如果有看不明白,請閱讀Android實踐《Https實現》和《MVC到MVP》相關博客進行了解;

二、xUtils3使用
1.首先看下我們項目結構,如下圖:

  common:項目公共庫,包含了該項目公共類,如QBaseActivity.java,在這裏執行xUtils的Activity注入;
  home:項目app,在這裏使用xUtils框架實現了一個簡單的列表功能,其中使用了註解、網絡請求(https)和圖片綁定等;
  ... ... 
2.xUtils的接入
在build.gradle構建文件中添加xUtils框架的依賴;
common/build.gradle
apply plugin: 'com.android.library'
android {
    ... ...
}
dependencies {
    ... ...
    compile 'com.alibaba:fastjson:1.1.54.android'
    //聲明xutils依賴
    compile 'org.xutils:xutils:3.3.38'
    testCompile 'junit:junit:4.12'
}
在AndroidManifest.xml中添加相關權限;
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.qunar.home">
    //聲明相關權限
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <application>
        ... ...
    </application>
</manifest>
3.xUtils @ContentView @ViewInject和@Event註解的使用;
在Application類中初始化xUtils框架;
home/src/main/com.qunar.home/QAppliction.java
public class QAplication extends Application{
    @Override
    public void onCreate() {
        super.onCreate();
        //初始化XUtils框架
        x.Ext.init(this);
        x.Ext.setDebug(BuildConfig.DEBUG); // 開啓debug會影響性能
    }
}
將Activity或者Fragment注入到xUtils框架,這裏我們抽象出BaseActivity;
common/src/main/com.qunar.common/QBaseActivity.java
public class QBaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //注入activity,用戶處理Activity以內的所有註解
        x.view().inject(this);
    }
}
通過在繼承QBaseActivity的類中等地方,使用@ContentView設置Activity或者Fragment等佈局,@ViewInject查找視圖對象和@Event註冊點擊事件 ;
home/src/main/com.qunar.home/render/view/RenderActivity.java
//代替setContentView()方法設置Activity的佈局
@ContentView(R.layout.activity_render)
public class RenderActivity extends QBaseActivity implements RenderContact.ViewQ {
    //代替findById獲取視圖對象
    @ViewInject(R.id.listview_render)
    private ListView renderListView;

    private RenderContact.PresenterQ renderPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        renderPresenter = new RenderPresenterQ(this);
        renderPresenter.showRenderList(this);
    }

    @Override
    public void setPresenter(RenderContact.PresenterQ presenter) {
        renderPresenter = presenter;
    }

    @Override
    public void initRenderListShow(RenderResultQ renderResult) {
        RenderListAdapter renderListAdapter = new RenderListAdapter(this, renderResult.getRenderListItemList());
        renderListView.setAdapter(renderListAdapter);
    }
    //通過@Event註解,註冊列表選項的點擊事件
    @Event(value = R.id.listview_render, type = AdapterView.OnItemClickListener.class)
    private void onImageItemClick(AdapterView<?> parent, View view, int position, long id) {
        Toast.makeText(this, "Title " + position + " is click", Toast.LENGTH_SHORT).show();
    }
}
問題1:在使用@ContentView等註解時,Android Studio提示錯誤Attribute value must be constant
分析1:檢查代碼是否爲Android的庫項目,該項目的R.java文件中的值不爲static final
處理1:在非Android的庫中使用註解;

4.xUtils網絡請求的使用;
在Presenter層,RenderPresenter層使用x.http().get()方法請求Render列表數據,創建RequestParams,並設置了https相關操作;
home/src/main/com.qunar.home/render/presenter/RenderPresenter.java
public class RenderPresenter implements RenderContact.PresenterQ {
    private RenderContact.ViewQ renderView;

    public RenderPresenter(RenderContact.ViewQ renderView) {
        this.renderView = renderView;
    }

    @Override
    public void start() {
    }

    @Override
    public void showRenderList(Context context) {
        //Presenter層,請求Render列表數據
        RequestParams renderParams = new RequestParams(QConfig.SERVER_URL + "RenderServlet");
        //採用https請求方法,獲取sslContext,設置socketFactory
        renderParams.setSslSocketFactory(HttpsTools.getSSLContext(context).getSocketFactory());
        x.http().post(renderParams, new Callback.CommonCallback<QRenderResult>() {
            @Override
            public void onSuccess(RenderResultQ result) {
                //調用View接口層方法,顯示Render列表數據
                renderView.initRenderListShow(result);
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                Toast.makeText(x.app(), ex.getMessage(), Toast.LENGTH_LONG).show();
            }

            @Override
            public void onCancelled(CancelledException cex) {
                Toast.makeText(x.app(), "cancelled", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFinished() {
            }
        });
    }
}
創建請求結果對象,使用@HttpResponse註解設置返回結果解析器;
//設置返回結果的Json解析器
@HttpResponse(parser = JsonResponseParser.class)
public class RenderResult extends QBaseResult {
    private List<RenderListItem> renderListItemList;
    public RenderResult(){}

    public List<RenderListItem> getRenderListItemList() {
        return renderListItemList;
    }
    public void setRenderListItemList(List<RenderListItem> renderListItemList) {
        this.renderListItemList = renderListItemList;
    }

    public class RenderListItem implements Serializable{
        private String imageUrl;
        private String itemTitle;
        private String itemDescription;

        public String getImageUrl() {
            return imageUrl;
        }

        public void setImageUrl(String imageUrl) {
            this.imageUrl = imageUrl;
        }

        public String getItemTitle() {
            return itemTitle;
        }

        public void setItemTitle(String itemTitle) {
            this.itemTitle = itemTitle;
        }

        public String getItemDescription() {
            return itemDescription;
        }

        public void setItemDescription(String itemDescription) {
            this.itemDescription = itemDescription;
        }
    }
}
創建Json結果解析器實現ResponseParser,覆蓋parse()方法,解析返回的json字符串;
public class JsonResponseParser implements ResponseParser {
    @Override
    public void checkResponse(UriRequest request) throws Throwable {
    }
    @Override
    public Object parse(Type resultType, Class<?> resultClass, String result) throws Throwable {
        //使用fastJson解析返回結果,這裏應該判斷返回類型分別解析parseObject或者parseArray
        return JSON.parseObject(result, resultClass);
    }
}
5.xUtils綁定圖片的使用;
在Render列表的適配器中,使用x.image().bind()方法將ImageView加載相關的圖片url,由於圖片是https請求,ImageOptions進行相關操作;
home/src/main/com.qunar.home/render/view/ RenderListAdapter.java
public class RenderListAdapter extends BaseAdapter {
    private List<RenderResult.RenderListItem> renderListItems;
    private final LayoutInflater layoutInflater;
    private ImageOptions imageOptions;

    public RenderListAdapter(final Context context, List<RenderResult.RenderListItem> renderListItems) {
        this.renderListItems = renderListItems;
        this.layoutInflater = LayoutInflater.from(context);
          
        //初始化加載圖片參數,詳情可以查看Android實踐《高效加載Bitmap》章節,https操作
        this.imageOptions = new ImageOptions.Builder().setSize(DensityUtil.dip2px(120), DensityUtil.dip2px(120)).setRadius(DensityUtil.dip2px(5)).setCrop(true).setImageScaleType(ImageView.ScaleType.CENTER_CROP).setLoadingDrawableId(R.mipmap.ic_launcher).setFailureDrawableId(R.mipmap.ic_launcher).setParamsBuilder(new ImageOptions.ParamsBuilder() {
                    @Override
                    public RequestParams buildParams(RequestParams params, ImageOptions options) {
                        //設置https SSLContext,SslSocketFactory等
                      params.setSslSocketFactory(HttpsTools.getSSLContext(context).getSocketFactory());
                        return params;
                    }
                }).build();
    }

    @Override
    public int getCount() {
        return renderListItems.size();
    }

    @Override
    public Object getItem(int position) {
        return renderListItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ItemHolder holder;
        if (convertView == null) {
            convertView = layoutInflater.inflate(R.layout.listitem_render, parent, false);
            holder = new ItemHolder();
            x.view().inject(holder, convertView);
            convertView.setTag(holder);
        } else {
            holder = (ItemHolder) convertView.getTag();
        }

        RenderResultQ.RenderListItem renderListItem = renderListItems.get(position);
        //使用x.image().bind()方法加載圖片
        x.image().bind(holder.imageView, renderListItem.getImageUrl(), imageOptions);
        holder.title.setText(renderListItem.getItemTitle());
        holder.description.setText(renderListItem.getItemDescription());

        return convertView;
    }

    private class ItemHolder {
        @ViewInject(R.id.listitem_render_imageview)
        private ImageView imageView;
        @ViewInject(R.id.listitem_render_title)
        private TextView title;
        @ViewInject(R.id.listitem_render_description)
        private TextView description;
    }
}
6.xUitls數據庫訪問的使用;
數據庫訪問,可查看官網,該Demo並沒有演示;

7.其它實現代碼,就不一一列舉了,請自行下載源碼進行了解。項目運行效果如下:

問題2:實現RenderServlet.java模擬接口時報錯:HTTP Status 405 - HTTP method GET is not supported by this URL
處理2:在Servlet中重寫的doGet方法不要調用super;

三、代碼庫
QProject:https://github.com/Pengchengxiang/QProject  分支:feature/xutils3

新技術,新未來!歡迎大家關注“1024工場”微信服務號,時刻關注我們的最新的技術訊息!(甭客氣!盡情的掃描或者長按!)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章