日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android开发--MVP demo+Jsoup在线小说阅读器(一)

發布時間:2023/12/10 Android 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android开发--MVP demo+Jsoup在线小说阅读器(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

因為最近身體不好又是偷懶了一陣子沒有更新…這次帶來的是一個在線的小說閱讀器.目前已經實現了基本的功能,完成了大概的框架,剩余的部分慢慢來更新。先放上源碼github https://github.com/CallMeSp/ToRead_MVP.git 求star。里面也有這個項目沒有應用mvp結構的源碼可以用來對比一下。
最近看了MVP框架,所以這個項目也采用了mvp框架,參考了mvp入門解析 、淺談mvp入門由于經驗不夠,有些粗糙。還使用了picasso圖片加載庫,Jsoup來實現網頁解析功能。先看一下代碼結構

然后看一些效果圖。


這就是用了MVP結構的代碼結構了,明顯感覺就是類的類別明顯增多了,不過解耦性明顯增強了,最大程度分離了view的交互和model的邏輯處理,view和model之間則通過presenter來溝通。
不過這又產生了一個問題:
這樣一個view和一個presenter對應一個界面,要是一個完整的項目,界面肯定不少,那和以view和presenter會暴增,這樣怎么辦呢?
利用組合思想。V和P是一一對應的,但是,我們可以把通用的VP提取出來。一個Activity implements 多個View,然后利用組合包含幾個P。舉個例子。有個LoginPresenter。我們現在要在登陸頁面中用到,另外在一個回復頁面,也需要做個快速登陸功能。那么我們可能需要在LoginActivity和ReplyActivity中都包含這個LoginPresenter,兩個Activity都各自去實現LoginView。可能ReplyActivity還有其他功能,他還要包含自己的ReplyPresenter,并實現自己的ReplyView。
利用組合來實現Presenter的復用,這個是MVP的優雅之一。但是別忘了不要持有View實例,記得detach。
然后言歸正傳,這個項目功能主要的實現依靠的是Jsoup的解析功能。來看一下bookbiz中根據搜索的書名來獲取書籍列表的這一段。

@Overridepublic void showbookslist(final String searchname){new Thread(new Runnable() {@Overridepublic void run() {try {books.clear();Document doc = Jsoup.connect("http://so.37zw.com/cse/search?q=" + searchname + "&click=1&s=2041213923836881982&nsid=").get();Elements items=doc.select("div.game-legend-a");for (Element Item : items) {Log.e("0","Item:"+Item);String title=Item.select("h3").text();String detail=Item.select("p.result-game-item-desc").text();String ur=Item.select("div.game-legend-a").attr("onclick");ur=ur.substring(17, ur.length() - 1);String writer=Item.select("p.result-game-item-info-tag").first().text();String IMG=Item.select("img").attr("src");book mybook=new book();mybook.setBook_name(title);mybook.setBook_writter(writer);mybook.setBook_details(detail);mybook.setBook_cover(IMG);mybook.setContenturl(ur);books.add(mybook);}presenter.updatelist(books);} catch (IOException e){e.printStackTrace();}}}).start();}

jsoup 是一款 Java 的HTML 解析器,可直接解析某個URL地址、HTML文本內容。它提供了一套非常省力的API,可通過DOM,CSS以及類似于JQuery的操作方法來取出和操作數據。
jsoup的主要功能如下:
從一個URL,文件或字符串中解析HTML;
使用DOM或CSS選擇器來查找、取出數據;
可操作HTML元素、屬性、文本;此處運用的就是使用DOM選擇器來查找和取出數據。本來相用正則來自己解析的..想想..還是算了吧..
http://www.open-open.com/jsoup/ 附上jsoup開發中文文檔。里面講的也很詳細。大家也可以寫寫demo來測試一下。下面看一下picasso的應用:

Picasso.with(myholder.itemView.getContext()).load(mybook.get(position).getBook_cover()).centerInside().fit().into(myholder.bookcover);

怎么樣是不是很簡潔…其實然后看看我原來自己沒有用這個庫自己實現的:

private void DoGetbitmap() {new Thread(new Runnable() {@Overridepublic void run() {for(int i=0;i<search_title_list.size();i++) {Log.e("0","url;"+search_bitmapurl.get(i));HttpGet httPost = new HttpGet(search_bitmapurl.get(i));HttpClient client = new DefaultHttpClient();// 請求超時client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000);// 讀取超時client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,10000);try {HttpResponse httpResponse = client.execute(httPost);byte[] bytes = new byte[1024];bytes = EntityUtils.toByteArray(httpResponse.getEntity());bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);search_bookvover_list.add(bitmap);} catch (IOException e) {Log.e("0", "fail get bitmap");e.printStackTrace();}Log.e("0", "success to get bitmap");}Log.e("0", "success to get bitmaps");Message.obtain(mhandeler,1).sendToTarget();}}).start();}

得設置各種Httpget、httpclient、然后害的response轉bytes轉bitmap然后再設置imageview簡直蠢到爆啊而且性能還很low。寫到這里想到了最近也正在學習retrofit和rxjava。學完后會對demo中的網絡請求和線程操作重新更好的處理一下。demo中還有一個亮點是在長按item的時候會彈出一個菜單,而且此時背景會虛化,這也是結合了前一陣的所學算是活學活用吧。來看一下代碼:

package com.sp.areader.view.fragment;import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.os.Build; import android.renderscript.Allocation; import android.renderscript.Element; import android.renderscript.RenderScript; import android.renderscript.ScriptIntrinsicBlur; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.TextView;import com.sp.areader.R;import java.util.ArrayList; import java.util.List;/*** Created by zhaoshuang on 16/8/29.* 彈出動畫的popupwindow*/ public class HintPopupWindow {private Activity activity;private WindowManager.LayoutParams params;private boolean isShow;private WindowManager windowManager;private ViewGroup rootView;private ViewGroup linearLayout;private final int animDuration = 250;//動畫執行時間/*** @param contentList 點擊item的內容文字* @param clickList 點擊item的事件* 文字和click事件的list是對應綁定的*/public HintPopupWindow(Activity activity, List<String> contentList, List<View.OnClickListener> clickList){this.activity = activity;windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);initLayout(contentList, clickList);}/*** @param contentList 點擊item內容的文字* @param clickList 點擊item的事件*/public void initLayout(List<String> contentList, List<View.OnClickListener> clickList){//這是根布局rootView = (ViewGroup) View.inflate(activity, R.layout.item_root_hintpopupwindow, null);linearLayout = (ViewGroup) rootView.findViewById(R.id.linearLayout);//格式化點擊item, 將文字和click事件一一綁定上去List<View> list = new ArrayList<>();for(int x=0; x<contentList.size(); x++){View view = View.inflate(activity, R.layout.item_hint_popupwindow, null);TextView textView = (TextView) view.findViewById(R.id.tv_content);View v_line = view.findViewById(R.id.v_line);textView.setText(contentList.get(x));linearLayout.addView(view);list.add(view);if(x == 0){v_line.setVisibility(View.INVISIBLE);}else{v_line.setVisibility(View.VISIBLE);}}for (int x=0; x<list.size(); x++){list.get(x).setOnClickListener(clickList.get(x));}//這里給你根布局設置背景透明, 為的是讓他看起來和activity的布局一樣params = new WindowManager.LayoutParams();params.width = WindowManager.LayoutParams.MATCH_PARENT;params.height = WindowManager.LayoutParams.MATCH_PARENT;params.format = PixelFormat.RGBA_8888;//背景透明params.gravity = Gravity.LEFT | Gravity.TOP;//當點擊根布局時, 隱藏rootView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {gonePopupWindow();}});rootView.setOnKeyListener(new View.OnKeyListener() {@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event) {//如果是顯示狀態那么隱藏視圖if(keyCode == KeyEvent.KEYCODE_BACK && isShow) gonePopupWindow();return isShow;}});}/*** 彈出選項彈窗* @param locationView 默認在該view的下方彈出, 和popupWindow類似*/public void showPopupWindow(View locationView){try {//這個步驟是得到該view相對于屏幕的坐標, 注意不是相對于父布局哦!int[] arr = new int[2];locationView.getLocationOnScreen(arr);linearLayout.measure(0, 0);//為view申請占 int,int大小的控件.若與實際大小不符合則會自動計算。Rect frame = new Rect();activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);//得到狀態欄高度float x = arr[0] + locationView.getWidth() - linearLayout.getMeasuredWidth();//float y = arr[1] - frame.top + locationView.getHeight();float y = arr[1] - frame.top;linearLayout.setX(x);linearLayout.setY(y+50);/*捕獲當前activity的布局視圖, 因為我們要動態模糊, 所以這個布局一定要是最新的,*這樣我們把模糊后的布局蓋到屏幕上時, 才能讓用戶感覺不出來變化*/View decorView = activity.getWindow().getDecorView();Bitmap bitmap = getBitmapByView(decorView);//這里是將view轉成bitmapsetBlurBackground(bitmap);//這里是模糊圖片, 這個是重點我會單獨講的, 因為效率很重要啊!!!//這里就是使用WindowManager直接將我們處理好的view添加到屏幕最前端windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);windowManager.addView(rootView, params);//這一步就是有回彈效果的彈出動畫, 我用屬性動畫寫的, 很簡單showAnim(linearLayout, 0, 1, animDuration, true);//視圖被彈出來時得到焦點, 否則就捕獲不到Touch事件rootView.setFocusable(true);rootView.setFocusableInTouchMode(true);rootView.requestFocus();rootView.requestFocusFromTouch();}catch (Exception e){e.printStackTrace();}}/*** 得到bitmap位圖, 傳入View對象*/public static Bitmap getBitmapByView(View view) {Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);view.draw(new Canvas(bitmap));return bitmap;}private void setBlurBackground(Bitmap bitmap) {Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth() / 3, bitmap.getHeight() / 3, false);Bitmap blurBitmap = getBlurBitmap(activity, scaledBitmap, 5);rootView.setAlpha(0);rootView.setBackgroundDrawable(new BitmapDrawable(blurBitmap));alphaAnim(rootView, 0, 1, animDuration);}public static Bitmap getBlurBitmap(Context context, Bitmap bitmap, int radius) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {return blurBitmap(context, bitmap, radius);}return bitmap;}/*** android系統的模糊方法* @param bitmap 要模糊的圖片* @param radius 模糊等級 >=0 && <=25*/public static Bitmap blurBitmap(Context context, Bitmap bitmap, int radius) {if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){//Let's create an empty bitmap with the same size of the bitmap we want to blurBitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);//Instantiate a new RenderscriptRenderScript rs = RenderScript.create(context);//Create an Intrinsic Blur Script using the RenderscriptScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));//Create the Allocations (in/out) with the Renderscript and the in/out bitmapsAllocation allIn = Allocation.createFromBitmap(rs, bitmap);Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);//Set the radius of the blurblurScript.setRadius(radius);//Perform the RenderscriptblurScript.setInput(allIn);blurScript.forEach(allOut);//Copy the final bitmap created by the out Allocation to the outBitmapallOut.copyTo(outBitmap);//recycle the original bitmapbitmap.recycle();//After finishing everything, we destroy the Renderscript.rs.destroy();return outBitmap;}else{return bitmap;}}public void gonePopupWindow(){goneAnim(linearLayout, 0.95f, 1, animDuration /3, true);isShow = false;}public WindowManager.LayoutParams getLayoutParams(){return params;}public ViewGroup getLayout(){return linearLayout;}/*** popupwindow是否是顯示狀態*/public boolean isShow(){return isShow;}private void alphaAnim(final View view, int start, int end, int duration){ValueAnimator va = ValueAnimator.ofFloat(start, end).setDuration(duration);va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float value = (float) animation.getAnimatedValue();view.setAlpha(value);}});va.start();}private void showAnim(final View view, float start, final float end, int duration, final boolean isWhile) {ValueAnimator va = ValueAnimator.ofFloat(start, end).setDuration(duration);va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float value = (float) animation.getAnimatedValue();view.setPivotX(view.getWidth());//設置縮放軸心點。以view為坐標view.setPivotY(0);view.setScaleX(value);view.setScaleY(value);Log.e("0","value="+value);}});va.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {if (isWhile) showAnim(view, end, 0.95f, animDuration / 3, false);}});va.start();}public void goneAnim(final View view, float start, final float end, int duration, final boolean isWhile){ValueAnimator va = ValueAnimator.ofFloat(start, end).setDuration(duration);va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float value = (float) animation.getAnimatedValue();view.setPivotX(view.getWidth());view.setPivotY(0);view.setScaleX(value);view.setScaleY(value);}});va.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {if(isWhile){alphaAnim(rootView, 1, 0, animDuration);goneAnim(view, end, 0f, animDuration, false);}else{try {windowManager.removeView(rootView);}catch (Exception e){e.printStackTrace();}}}});va.start();} }

代碼里面重要的功能都有注釋就不用多說了吧。其它的就是各種邏輯的處理了,在各個activity間跳轉,也是很簡單,想下載demo的拉到最上面點進我的github來下載。這篇博客就到這吧,才疏學淺也寫不出什么長篇大論。
立個flag:
1.完善小說緩存下載功能,要求實現斷點重連后臺下載。
2.網絡請求用retrofit改善
3.線程的處理用rxjava改善

總結

以上是生活随笔為你收集整理的Android开发--MVP demo+Jsoup在线小说阅读器(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。