当前位置: 代码迷 >> Android >> 仿照知乎Android APP四
  详细解决方案

仿照知乎Android APP四

热度:74   发布时间:2016-04-28 01:02:54.0
模仿知乎Android APP四

这一篇blog其实是没有什么新的知识点,就是接着上一篇的。然后会在FirstFragment中的tab01界面上使用一个ListView,然后这个listview会显示从网路上读取得到的数据。数据包括图片和文字,使用ImageLoader去下载并管理图片的一些处理,包括二级缓存(内存缓存和本地缓存)。

以前的代码没有修改,是在FirstFragment的tab01这个内容Fragment里面去处理。

主要的思路跟ListView使用ImageLoader去下载图片显示一样。首先需要配置Application,里面对ImageLoader做初始化配置。然后在tab01,也就是显示内容的Fragment中使用LIstVIew控件,自定义适配器,然后使用Handler机制绑定适配器。使用Fragment'可以把它当做Activity那样子去使用,当时需要注意的就是Fragment的生命周期以及他们执行顺序,执行效果。其中,假如是使用ViewPager+Fragment的时候特别需要注意,我们的ViewPager'会缓存相邻界面,比如当前界面是1,滑动到2的时候2界面会缓存1界面(此时还没有滑动到3界面),当滑动到3界面的时候,他只会缓存2界面,这时候关于1界面就会被销毁。假如需要缓存多个界面,不用去考虑性能优化可以使用mViewPager.setOffscreenPageLimit(2); 这个方法,他可以缓存两个Fragment页面。上代码首先是tab01的界面:
废话不多说,上代码:

首先是Tab01的布局,就是一个ListView

<?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="match_parent"    android:gravity="center"    android:orientation="vertical" >    <ListView        android:id="@+id/tab_01_listView"        android:layout_width="match_parent"        android:layout_height="match_parent" >    </ListView></LinearLayout>

到LIstView所绑定数据条目的显示界面的代码:包含一个ImageView和两个TextView

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <ImageView        android:src="@drawable/ic_launcher"        android:id="@+id/id_ListView_imageView"        android:layout_width="72dp"        android:layout_height="72dp"        android:layout_margin="5dp"        android:adjustViewBounds="true"        android:contentDescription="@string/contentDescriptionImage"        android:scaleType="centerCrop" />    <TextView        android:textStyle="bold"        android:id="@+id/news_list_tit"        android:layout_width="wrap_content"        android:layout_height="25dp"        android:layout_alignParentTop="true"        android:layout_marginLeft="16dp"        android:layout_toRightOf="@id/id_ListView_imageView"        android:text="DFGDFGDFGD"        android:textSize="18sp"         android:textColor="#000000"/>    <TextView        android:layout_marginTop="3dp"        android:textSize="15sp"        android:textColor="#000000"        android:id="@+id/news_list_cont"        android:layout_width="wrap_content"        android:layout_height="25dp"        android:layout_alignLeft="@+id/news_list_tit"        android:layout_below="@id/news_list_tit"        android:gravity="bottom"        android:text="00000000000" />    <TextView        android:textSize="12sp"        android:textStyle="italic"        android:textColor="#000000"        android:id="@+id/news_list_gentie"        android:layout_width="100dp"        android:layout_height="25dp"        android:layout_alignParentRight="true"        android:layout_below="@+id/news_list_cont"        android:gravity="right"        android:text="520跟帖" /></RelativeLayout>


然后到Tab01的代码,他的功能是开一条线程去完成xml数据的现在,然后下载完成之后通过Handle机制去绑定适配器,没撒好说的,跟之前的一样。还有就是设置ImageLoader下载图片的Options,包括一些显示效果,没有下载完成或者URL错误的时候需要显示的代替图片等等。

import java.util.ArrayList;import java.util.List;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ListView;import android.widget.Toast;import com.example.mytoolbar_04.R;import com.example.mytoolbar_04.fragment.adapter.MyTab01BaseAdapter;import com.example.mytoolbar_04.fragment.domain.NewsInfo;import com.example.mytoolbar_04.fragment.service.TabNewsService;import com.nostra13.universalimageloader.core.DisplayImageOptions;import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;public class Tab01 extends Fragment{	public static final int OK = 1;	public static final int ERROR = -1;	private ListView mTab01ListView;	private View mTab01LayoutView;	private List<NewsInfo> datas;	private DisplayImageOptions options;	@Override	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)	{		mTab01LayoutView = inflater.inflate(R.layout.tab01, null);		mTab01ListView = (ListView) mTab01LayoutView.findViewById(R.id.tab_01_listView);		datas = new ArrayList<NewsInfo>();		new MyLoaderNewInfo(datas, mHandler).start();		options = new DisplayImageOptions.Builder().showStubImage(R.drawable.ic_launcher)		    .showImageForEmptyUri(R.drawable.ic_empty).showImageOnFail(R.drawable.ic_error)		    .displayer(new RoundedBitmapDisplayer(20)).build();		return mTab01LayoutView;	}	//绑定适配器	private Handler mHandler = new Handler()	{		@SuppressWarnings("unchecked")    public void handleMessage(Message msg)		{			if (msg.what == OK)			{				MyTab01BaseAdapter adapter = new MyTab01BaseAdapter(getActivity(), options,				    (List<NewsInfo>) msg.obj);				mTab01ListView.setAdapter(adapter);			}			if (msg.what == ERROR)			{				Toast.makeText(getActivity(), "获取失败", Toast.LENGTH_SHORT).show();			}		};	};}class MyLoaderNewInfo extends Thread{	private List<NewsInfo> datas;	private Handler mHandler;	public MyLoaderNewInfo(List<NewsInfo> datas, Handler mHandler)	{		this.datas = datas;		this.mHandler = mHandler;	}	/* (non-Javadoc)	 * @see java.lang.Thread#run()	 * 下载xml基础数据	 */	@Override	public void run()	{		try		{			datas.addAll(TabNewsService.getDatas());			Message msg = Message.obtain();			msg.what = Tab01.OK;			msg.obj = datas;			mHandler.sendMessage(msg);		} catch (Exception e)		{			e.printStackTrace();			mHandler.sendEmptyMessage(Tab01.ERROR);		}	}}
到获取XML基础数据的Service类了,也没撒好说的,;利用Pull破解器解析xml数据,返回一个List集合

import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;import java.util.ArrayList;import java.util.List;import org.xmlpull.v1.XmlPullParser;import org.xmlpull.v1.XmlPullParserException;import android.util.Xml;import com.example.mytoolbar_04.fragment.domain.NewsInfo;/** * @author Administrator liweijie * 初次获取网络基本数据 */public class TabNewsService{	// 192.168.1.137mylist1.xml	/**	 * 请求xml数据	 * @return	 * @throws Exception 	 * @throws XmlPullParserException 	 */	public static List<NewsInfo> getDatas() throws XmlPullParserException, Exception	{		String path = "http://172.21.123.11:8080/web/News.xml";			HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();			conn.setReadTimeout(5000);			conn.setConnectTimeout(5000);			conn.setRequestMethod("GET");			if (200 == conn.getResponseCode())			{				InputStream stream = conn.getInputStream();				return parXML(stream);			}		return null;	}	/**	 * 解析xml数据	 * @param stream	 * @return	 * @throws XmlPullParserException	 * @throws Exception	 */	private static List<NewsInfo> parXML(InputStream stream) throws XmlPullParserException, Exception	{		List<NewsInfo> datas = new ArrayList<NewsInfo>();		NewsInfo news = null;		XmlPullParser parser = Xml.newPullParser();		parser.setInput(stream, "UTF-8");		int event = parser.getEventType();		while (event != XmlPullParser.END_DOCUMENT)		{			switch (event)			{			case XmlPullParser.START_TAG:				if("picture".equals(parser.getName()))				{					news = new NewsInfo();					news.setTitle(parser.getAttributeValue(0));					break;				}				if("path".equals(parser.getName()))				{					news.setPath(parser.nextText());					break;				}				if("content".equals(parser.getName()))				{					news.setContent(parser.nextText());					break;				}				if("fllow".equals(parser.getName()))				{					news.setPeopleIN(parser.nextText());					break;				}				break;			case XmlPullParser.END_TAG:				if ("picture".equals(parser.getName()))				{					datas.add(news);					news = null;					break;				}				break;			}			event = parser.next();		}		System.out.println(datas.size());		return datas;	}}
domian类

public class NewsInfo{	private String path;	private String title;	private String content;	private String peopleIN;	public NewsInfo(){};	public NewsInfo(String path, String title, String content, String peopleIN)  {	  super();	  this.path = path;	  this.title = title;	  this.content = content;	  this.peopleIN = peopleIN;  }	public String getPath()	{		return path;	}	public void setPath(String path)	{		this.path = path;	}	public String getTitle()	{		return title;	}	public void setTitle(String title)	{		this.title = title;	}	public String getContent()	{		return content;	}	public void setContent(String content)	{		this.content = content;	}	public String getPeopleIN()	{		return peopleIN;	}	public void setPeopleIN(String peopleIN)	{		this.peopleIN = peopleIN;	}}


最后,是自定义的Adapter类,这样就基本完成了ListVIew的显示数据了

import java.util.ArrayList;import java.util.Collections;import java.util.LinkedList;import java.util.List;import android.content.Context;import android.graphics.Bitmap;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import com.example.mytoolbar_04.MainActivity;import com.example.mytoolbar_04.R;import com.example.mytoolbar_04.fragment.domain.NewsInfo;import com.nostra13.universalimageloader.core.DisplayImageOptions;import com.nostra13.universalimageloader.core.ImageLoader;import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;public class MyTab01BaseAdapter extends BaseAdapter{	private LayoutInflater inflater;	private List<NewsInfo> datas = new ArrayList<NewsInfo>();	private DisplayImageOptions options;	private ImageLoader imageLoader = MainActivity.getImageLoader();	public MyTab01BaseAdapter(Context activity, DisplayImageOptions options, List<NewsInfo> datas)	{		this.datas.addAll(datas);		inflater = LayoutInflater.from(activity);		this.options = options;		System.out.println("ok222");	}	public int getCount()	{		return datas.size();	}	public Object getItem(int position)	{		return datas.get(position);	}	@Override	public long getItemId(int position)	{		return position;	}	private NewsInfo news;	@Override	public View getView(int position, View convertView, ViewGroup parent)	{		ViewHolder holder = null;		if (convertView == null)		{			holder = new ViewHolder();			convertView = inflater.inflate(R.layout.newlistview_layout_item, null);			holder.imageView = (ImageView) convertView.findViewById(R.id.id_ListView_imageView);			holder.mTitle = (TextView) convertView.findViewById(R.id.news_list_tit);			holder.mContent = (TextView) convertView.findViewById(R.id.news_list_cont);			holder.mFllow = (TextView) convertView.findViewById(R.id.news_list_gentie);			convertView.setTag(holder);		} else		{			holder = (ViewHolder) convertView.getTag();		}		System.out.println("66666");		news = datas.get(position);		holder.mTitle.setText(news.getTitle());		holder.mContent.setText(news.getContent());		holder.mFllow.setText(news.getPeopleIN());		imageLoader.displayImage(news.getPath(), holder.imageView,options,new FirstDisplatListener());		return convertView;	}	class ViewHolder	{		ImageView imageView;		TextView mTitle;		TextView mContent;		TextView mFllow;	}	private static class FirstDisplatListener extends SimpleImageLoadingListener	{		static final List<String> diaplayImages = Collections		    .synchronizedList(new LinkedList<String>());// 线程安全		@Override		public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage)		{			if (loadedImage == null)			{				ImageView imageView = (ImageView) view;				boolean firstDisplay = !diaplayImages.contains(imageUri);				if (firstDisplay)// 不存在的时候,这时候是属于第一次显示,使用一个渐变的动画,然后把该uri对应的imageview存放到list中				{					FadeInBitmapDisplayer.animate(imageView, 500);					diaplayImages.add(imageUri);				}			}		}	}}
还有Application类,需要在Application界面使用name属性去使用它

import java.io.File;import android.app.Application;import android.content.Context;import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;import com.nostra13.universalimageloader.core.ImageLoader;import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;import com.nostra13.universalimageloader.core.assist.QueueProcessingType;import com.nostra13.universalimageloader.utils.StorageUtils;public class MyApplication extends Application{	@Override	public void onCreate()	{		super.onCreate();		initImageLoader(getApplicationContext());	}	private static void initImageLoader(Context context)	{		File cache = StorageUtils.getOwnCacheDirectory(context, "operaPic/cache");		ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(context)		    .threadPriority(Thread.NORM_PRIORITY - 2)		    .threadPoolSize(4)		    .discCache(new UnlimitedDiscCache(cache))		    .denyCacheImageMultipleSizesInMemory()		    .discCacheFileNameGenerator(new Md5FileNameGenerator())		    .tasksProcessingOrder(QueueProcessingType.LIFO)		    .writeDebugLogs()		    .build();		ImageLoader.getInstance().init(configuration);	}}

我这篇demo是使用ViewPager+Fragment的,没有使用mViewPager.setOffscreenPageLimit(2)这个API,所以只会默认缓存一个页面

下面是效果图:可以注意到当移动到2界面返回1界面的时候没有1界面变化,但是当从3界面移动到1界面的时候他会从新去调用onCreateView方法去重新创建Fragment的view。当LeftMenuFragment的切换过程发现其他的Fragment之前切换是不会影响他的布局的,因为我们显示FirstFragment和SecondFragment以及ThirdFragment的时候是先hide在shou,不会对Fragment的显示造成什么样的影响。









  相关解决方案