Android 开发小框架

3 篇文章 0 订阅
2 篇文章 0 订阅

正式接触Android也有差不多一年多的时间了,在这一年里多多少少也有一些成长和积累。今天就跟大家分享一下这一年多以来的给验与积累。     

这一年多以来在公司多多少少也做出三四个小项目,虽然不多但也是一些积累。先说用到的技术点(不分先后):

  1. 多线程与线程同步
  2. 串口通讯
  3. 数据结构的封闭(Java是没有数据结构的,下面会详细介绍这个结构封闭)
  4. AOP切面编程
  5. AES加解密
  6. HTTP网络通讯
  7. MVVM的封装
  8. 数据库(SqlLite)的使用
  9. 自定义注解
  10. 条件编译的设置
  11. MsgBox的封装

暂先列这几个吧,至于自下定义控件、和控件的使用、还有常 用的转换函数等等类似这样的我都没有列入技术点。

以上的技术点我做了一个叫做【App】的小项目,我叫做Android开发小框架。说是框架其实也就是一些函数封装,说是函数封装吧,其实也包含了一些框架:

  1. AOP框架
  2. 所有的Activity的基类(BaseActivity)。该对象的派生类支持动态申请权限、和支持长按的功能。还有一些常用函数。
  3. 所有实体对象的基类(BaseEntity)。从该类派生的对象支持LoadJson和ToJson的功能。
  4. 所有数据结构的基类(StructBase)。该类是一个数据结构的基类,把一个数据结构封装成一个实体对象,支持loadJson、ToJson、LoadBinary等功能。
  5. 所有数据库操作的基类(DataAccess)。所有从该类派生的对象支持Insert、Updata、Delete、SelectAll方法。不用写语句即可使用。
  6. 串口通讯的基类(ComDevice)。该对象的派生类支持串口通讯的功能,使用时就和Tcp通讯一样方便。

先贴一下该小框架的下在地址:

https://download.csdn.net/download/bluesky_wypeng/10738057

程序结构图:

下面依次介绍这个小框架。

串口通讯

串口通讯的低层

低层通讯有两个对象,一个与驱动进行交互,一个是转换后的一个封闭。说白了都是低层交互。在低层交互的基础上我又做了一层封装,该封装把一些不用的参数信息隐藏然后放出三个接口:

打开串口:

public void Open(final String comport, final int baudrate, final int databits,
                     final int stopbits, final char parity) 

发送数据(该方法发送数据后由IComPortRecv的派生类进行处理):

 /**
     * 发送数据
     *
     * @param data
     * @return 返回发送的数据长度
     */
    public int SendData(byte[] data)

发送数据支持回调:

/**
     * 发送数据
     * @param data 发送的数据
     * @param recvCallBack 收到数据后的事件处理
     */
    public void SendData(byte[] data,IAsynListener recvCallBack) 
IComPortRecv接口声明如下:
package ComPort;

/**
 * 串口数据回调事件
 * Created by 王彦鹏 on 2018-01-31.
 */

public interface IComPortRecv {
    /**
     * 串口数据回调
     * @param data
     * @param size
     */
    void RecvData(byte[] data, int size);
}

串口通讯代码清单:

SerialPort:

/*
 * Copyright 2009 Cedric Priscal
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */

package android_serialport_api;

import android.util.Log;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class SerialPort {

	private static final String TAG = "SerialPort";

	/*
	 * Do not remove or rename the field mFd: it is used by native method close();
	 */
	private FileDescriptor mFd;
	private FileInputStream mFileInputStream;
	private FileOutputStream mFileOutputStream;

	public SerialPort(File device, int baudrate, int databits, int stopbits, char parity) throws SecurityException, IOException {

		/* Check access permission */
		if (!device.canRead() || !device.canWrite()) {
			try {
				/* Missing read/write permission, trying to chmod the file */
				Process su;
				su = Runtime.getRuntime().exec("/system/xbin/su");
				String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
						+ "exit\n";
				su.getOutputStream().write(cmd.getBytes());
				if ((su.waitFor() != 0) || !device.canRead()
						|| !device.canWrite()) {
					throw new SecurityException();
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new SecurityException();
			}
		}

		mFd = open(device.getAbsolutePath(), baudrate, databits,stopbits,parity);
		if (mFd == null) {
			Log.e(TAG, "native open returns null");
			throw new IOException();
		}
		mFileInputStream = new FileInputStream(mFd);
		mFileOutputStream = new FileOutputStream(mFd);
	}

	// Getters and setters
	public InputStream getInputStream() {
		return mFileInputStream;
	}

	public OutputStream getOutputStream() {
		return mFileOutputStream;
	}

	// JNI
	private native static FileDescriptor open(String path, int baudrate, int databits, int stopbits, char parity);
	public native void close();
	static {
		System.loadLibrary("serial_port");
	}
}
SerialPortFinder:
/*
 * Copyright 2009 Cedric Priscal
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */

package android_serialport_api;

import android.util.Log;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.Iterator;
import java.util.Vector;

public class SerialPortFinder {

	public class Driver {
		public Driver(String name, String root) {
			mDriverName = name;
			mDeviceRoot = root;
		}
		private String mDriverName;
		private String mDeviceRoot;
		Vector<File> mDevices = null;
		public Vector<File> getDevices() {
			if (mDevices == null) {
				mDevices = new Vector<File>();
				File dev = new File("/dev");
				File[] files = dev.listFiles();
				int i;
				for (i=0; i<files.length; i++) {
					if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {
						Log.d(TAG, "Found new device: " + files[i]);
						mDevices.add(files[i]);
					}
				}
			}
			return mDevices;
		}
		public String getName() {
			return mDriverName;
		}
	}

	private static final String TAG = "SerialPort";

	private Vector<Driver> mDrivers = null;

	Vector<Driver> getDrivers() throws IOException {
		if (mDrivers == null) {
			mDrivers = new Vector<Driver>();
			LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
			String l;
			while((l = r.readLine()) != null) {
				// Issue 3:
				// Since driver name may contain spaces, we do not extract driver name with split()
				String drivername = l.substring(0, 0x15).trim();
				String[] w = l.split(" +");
				if ((w.length >= 5) && (w[w.length-1].equals("serial"))) {
					Log.d(TAG, "Found new driver " + drivername + " on " + w[w.length-4]);
					mDrivers.add(new Driver(drivername, w[w.length-4]));
				}
			}
			r.close();
		}
		return mDrivers;
	}

	public String[] getAllDevices() {
		Vector<String> devices = new Vector<String>();
		// Parse each driver
		Iterator<Driver> itdriv;
		try {
			itdriv = getDrivers().iterator();
			while(itdriv.hasNext()) {
				Driver driver = itdriv.next();
				Iterator<File> itdev = driver.getDevices().iterator();
				while(itdev.hasNext()) {
					String device = itdev.next().getName();
					String value = String.format("%s (%s)", device, driver.getName());
					devices.add(value);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return devices.toArray(new String[devices.size()]);
	}

	public String[] getAllDevicesPath() {
		Vector<String> devices = new Vector<String>();
		// Parse each driver
		Iterator<Driver> itdriv;
		try {
			itdriv = getDrivers().iterator();
			while(itdriv.hasNext()) {
				Driver driver = itdriv.next();
				Iterator<File> itdev = driver.getDevices().iterator();
				while(itdev.hasNext()) {
					String device = itdev.next().getAbsolutePath();
					devices.add(device);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return devices.toArray(new String[devices.size()]);
	}
}

业务封装:

ComDevice:
package ComPort;

import android.content.Context;
import android.content.ContextWrapper;
import android.os.Process;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import Helper.EnjoyTools;
import Helper.Log;
import Listener.IAsynListener;
import android_serialport_api.SerialPort;
import android_serialport_api.SerialPortFinder;

/**
 * Created by 王彦鹏 on 2018-01-31.
 */

public class ComDevice extends ContextWrapper {
    private SerialPort mSerialPort=null;
    private InputStream inputStream = null;
    private OutputStream outputStream = null;
    private byte[] buffer=new byte[128];
    private int bufferSize=0;
    private Object syncobj = new Object();
    private boolean[] recvFlag=new boolean[]{false};
    private String comName="";
    private Context ctx;
    private ExecutorService executor;
    /**
     * 收到数据的处理事件
     */
    private IAsynListener RecvCallBack;

    public List<String> ComDevicesList = new ArrayList<String>();

    class callTAsk implements Callable<Integer> {
        private  byte[] buf;

        public callTAsk( byte[] data)
        {
            buf=data;
        }

        @Override
        public Integer call() throws Exception {
            recvFlag[0] = true;
            if (RecvCallBack!=null)
            {
                Log.write(comName, "收到数据执行回调");
                RecvCallBack.onFinish(buf,buf.length);
                Log.write(comName, "接收回调清除");
                //RecvCallBack=null;
            }
            else
            {
                Log.write(comName, "收到数据但未发现回调地址");
            }
            if (ctx instanceof IComPortRecv) {
                ((IComPortRecv) ctx).RecvData(buf, buf.length);
            }
            return 0;
        }
    };

        private Runnable mRunnable = new Runnable() {
        public void run() {
            Object obj=new Object();
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            while (!executor.isShutdown()) {
                try {
                    synchronized (syncobj) {
                        int size; //读取数据的大小
                        if (inputStream != null) {
                            size = inputStream.available();
                            if (size > 0) {
                                size = inputStream.read(buffer);
                                byte[] buf = new byte[size];
                                bufferSize=size;
                                System.arraycopy(buffer, 0, buf, 0, size);
                                Log.write(comName, String.format(" %s 收到数据:%s", comName, EnjoyTools.ByteArrayToHexString(buf)));
                                ExecutorService executor = Executors.newSingleThreadExecutor();
                                executor.submit(new callTAsk(buf));//将任务提交给线程池
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                    synchronized (obj)
                    {
                        obj.wait(10);
                    }

                } catch (Exception e) {

                }
                /*if (inputStream != null) {
                    mHandler.postDelayed(mRunnable, 10);  //给自己发送消息,自运行
                }*/
            }
            Log.write(comName, String.format(" %s 关闭", comName));
        }
    };
    public ComDevice(Context base)  {
        super(base);
        ctx=this;

        SerialPortFinder serialPortFinder=new SerialPortFinder();
        String[] entryValues = serialPortFinder.getAllDevicesPath();

        for (int i = 0; i < entryValues.length; i++) {
            ComDevicesList.add(entryValues[i]);
        };

    }

    public void destroy()
    {
        Log.write(comName, String.format(" %s 准备退出",comName));
        executor.shutdown();
        Close();
        Log.write(comName, String.format(" %s 已退出",comName));
    }

    /**
     * 打开串口
     */
    public void Open(final String comport, final int baudrate, final int databits,
                     final int stopbits, final char parity) throws Exception {
        comName = comport;
        mSerialPort = new SerialPort(new File(comport), baudrate, databits, stopbits, parity);
        //获取打开的串口中的输入输出流,以便于串口数据的收发
        inputStream = mSerialPort.getInputStream();
        outputStream = mSerialPort.getOutputStream();
        Log.write(comName, String.format("打开串口:%s", comport));
        executor = Executors.newSingleThreadExecutor();
        executor.execute(mRunnable);
    }

    /**
     * 关闭串口
     */
    public void Close() {
        try {
            mSerialPort.close();
            inputStream.close();
            outputStream.close();
            inputStream=null;
            outputStream=null;
            mSerialPort.close();
            Log.write(comName, String.format("串口 %s 已关闭", comName));
        } catch (IOException e) {
            Log.write(comName, String.format("关闭串口 %s 异常:%s", comName, e.toString()));
            return;
        }

    }

    /**
     * 发送数据
     *
     * @param data
     * @return 返回发送的数据长度
     */
    public int SendData(byte[] data) {
        synchronized (syncobj) {
            recvFlag[0] = false;
            if (outputStream != null) {
                Log.write(comName, String.format("%s 发送数据:%s", comName, EnjoyTools.ByteArrayToHexString(data)));
                try {
                    outputStream.write(data);
                } catch (IOException e) {
                    Log.write(comName, String.format("%s 发送失败:", comName, e.toString()));
                }
                return data.length;
            } else {
                return 0;
            }
        }
    }


    /**
     * 发送数据
     * @param data 发送的数据
     * @param recvCallBack 收到数据后的事件处理
     */
    public void SendData(byte[] data,IAsynListener recvCallBack) {
        synchronized (syncobj) {
            Log.write(comName, "开始发送数据");
            if (outputStream != null) {
                RecvCallBack=recvCallBack;
                Log.write(comName, String.format("%s 发送数据:%s", comName, EnjoyTools.ByteArrayToHexString(data)));
                try {
                    outputStream.write(data);
                } catch (IOException e) {
                    Log.write(comName, String.format("%s 发送失败:", comName, e.toString()));
                }
            } else {
                recvCallBack.onError(this,new Exception("设备未连接"));
            }
        }
        Log.write(comName, "数据发送完毕");
    }

}


串口接收接口的声明(IComPortRecv):

package ComPort;

/**
 * 串口数据回调事件
 * Created by 王彦鹏 on 2018-01-31.
 */

public interface IComPortRecv {
    /**
     * 串口数据回调
     * @param data
     * @param size
     */
    void RecvData(byte[] data, int size);
}

注解:

这些注解都是为了AOP和数据库基类自动生成语句来使用的,看看即可。在此只列出一个AOP注解的定义:

package Annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import Filter.IFilter;


@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Filter {
	Class<?>[] value() default {IFilter.class};// 属性类型为Class;

}

对象太多,以下只贴图了,请多包涵,如需要请下载这个小框架来研究吧,有任何问题可以在线回复。

BaseActivity接口:

数据库基类:

AOPDemo:

数据结构的一个Demo

AOP工厂类

网络通讯类(多线程)

几个MVVM用到的控件

有问题大家可以询问。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值