android下PDF格式的地图数据的显示------超大PDF页面显示策略(二)

        下面简要介绍一下项目中的一些经验。

技术总结:

1.缓存系统

缓存系统的原理很简单。这里就不具体介绍。

public class Cache {
	CacheData[] cachePool=null;
	int size=10;
	public Cache(int dataSize)
	{
		size=dataSize;
		cachePool=new CacheData[size];//仅仅分配size个cacheData指针
		int i;
		for(i=0;i<size;i++)
		{
			cachePool[i]=new CacheData();
		}
	}
	public Bitmap getBitmap(int currentRes,String fileName)
	{
		int i;
		
		for(i=0;i<size;i++)
		{		
			//把不在当前比例尺的缓存清空
			if(cachePool[i].Resolution != currentRes && cachePool[i].data != null)
			{
				Log.d("xiaoxiao", "clear "+i+"res:"+currentRes);
				cachePool[i].clear();				
			}
		}
		for(i=0;i<size;i++)
		{
			if(fileName.equals(cachePool[i].fileName))
			{
				cachePool[i].usedCount+=1;
				//Log.d("xiaoxiao", "cache!");
				int j=0;
				for(j=0;j<size;j++)
				{
					if(j!=i)
					cachePool[j].usedCount--;
				}
				return cachePool[i].data;
			}
		}
		
		//Log.d("xiaoxiao", "can not find "+fileName);
		//未找到
		File file=new File(fileName);
		if(!file.exists())
			Log.d("xiaoxiao", "cachesys: file is not exists "+fileName);
		
		//文件存在 也有可能加载图片失败
		Bitmap map=BitmapFactory.decodeFile(fileName);
		if(map==null)
		{
			//尝试10次重新加载
			int j;
			int times=0;
			for(j=0;j<times;j++)
			{
				Log.d("xiaoxiao", "try "+j+" decode file error:"+fileName);
				map=BitmapFactory.decodeFile(fileName);
				if(map!=null)
					break;					
			}
			if(map==null)
			{	
				Log.d("xiaoxiao", "decode file after "+times+" times even error:"+fileName);
				return null;
			}
		}
		int targetId=-1;
		for(i=0;i<size;i++)
		{
			if(cachePool[i].data==null)
			{
				targetId=i;
				break;
			}
		}
		if(i>=size)
		{
			targetId=0;
			for(i=1;i<size;i++)
			{
				if(cachePool[targetId].usedCount > cachePool[i].usedCount)
					targetId=i;
			}
		}
		//Log.d("xiaoxiao","cache in "+targetId+fileName);
		cachePool[targetId].fillData(fileName, map, currentRes);
		//cachePool[targetId].debug();
		return map;
	}
}
2.android jni的使用

贴再这里,算是复习吧。

public class FpdfembActivity extends Activity {
	/** Called when the activity is first created. */	
	static
	{
		System.loadLibrary("fpdfemb");
	}
	public native static int openPDF(String pdfPath);
	public native static int closePDF();
.....
}
3.实现自己的View之刷新界面

在自己实现的view里面,定义一个handler即可实现消息的响应。注意,view要刷新界面,只有自己在ui线程中调用invalidate()。工作线程要让view刷新界面,最好用发消息的形式,不建议直接调用invalidate函数。

要响应消息,在view里面定义一个handler并实现handlerMessage函数即可。

	mHandler=new Handler(){
			//接收到消息后处理  
            public void handleMessage(Message msg)  
            {  
                   switch (msg.what)  
                   {  
                   case PDFView.REFRESH:  
                          PDFView.this.invalidate();        //刷新界面  
                          break;  
                   }  
                   super.handleMessage(msg);  
            }          
		};
注:PDFView.REFRESH是一个宏定义,值为1。

4.实现自己的View之发送刷新消息

在工作线程中要给UI线程发送消息,很简单。只有三句话:

			Message message=new Message();
	    	        message.what=PDFView.REFRESH;
			PDFView.this.mHandler.sendMessage(message);

5.工作线程

对于解析PDF这样需要很长时间需要很多计算量的任务来说,有必要交给工作线程来做。工作线程的实现,推荐以下模型:

public class PageThread extends Thread{
		private Vector<PageData> msgVector=new Vector<PageData>();	
		public void reset()
		{
			msgVector.clear();
		}
		public synchronized void sendMessage(PageData msg){
				//msgVector.add(msg);
			Log.d("xiaoxiao","msg imgPath: "+msg.imgPath);
			msgVector.add(0,msg);
		}
		
		public void run(){		
			while(true){.......}
msgVector是任务队列。reset函数可以清空任务队列。sendMessage函数负责填充任务队列。
在while循环中,不停的从队列中取出任务并完成任务即可。


经验总结:

        1.每次编译完ndk后,记得清空工程,不然难保证工程中用的是最新的编译库。

        2.嵌入式设备上,最忌讳内存泄露,所以,写完代码后,最后仔细检查一下看看有无内存泄露的地方。最后,把关键的函数用for循环跑上1000遍,如果内存增加不多,说明代码质量不错。

        3.写嵌入式上的程序,忌讳内存平凡申请和释放。最好自己做内存管理,即一上来就申请一个很大的内存块,以后每次需要内存,就从自己申请到的大内存中分一块出来用。

        4.在嵌入式设备上,为了提高效率,减少计算量,常用缓存机制。例如,在本项目中,为了不减少绘图次数,将渲染后的bitmap存为png图片,下次需要显示的时候,直接贴图即可。

        5.加载自己写的ndk库只能在activety里面。(在其他地方加载没有成功)

        6.想要在自己实现的view里面拿到view的大小,必须在onDraw函数里面获取。因为view必须在初始化结束后才知道自己的尺寸。

        7.在缓存中,一般用的是最少使用替换策略。在更新每个缓存元素的使用次数的时候,最好访问一次,当前元素使用次数加一,同时,其他的使用次数减一。

        8.对于使用第三方库,每次调用函数后,最后都判断返回值,否则,程序会出现很多的安全隐患。

        9.java中的线程安全,不光是访问冲突那么简单。例如线程安全的vector,如果有两个线程一个遍历vector,另外一个clear vertor,会出现很多意想不到的情况,最容易出现的是访问越界。这就是所谓的“逻辑冲突”。

        10.android的刷新机制的理解:每一次invalidate(),不一定会触发一次刷新操作。10次连续的invalidate,可能刷新其中的6次。这是操作系统为了减少刷新次数而优化设计的机制。

        11.在ondraw函数和onTouchEvent等消息响应函数,能够做尽量少的事情尽量少做,这样能够保证很好的响应速度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值