1、我们有时会遇到如下问题。当有两个或多个UI类展示界面大体相同,但需要展示不同的内容,并且这些类之间都要相互交换或者刷新数据。繁琐的做法是为每一个UI类都建立新的布局,这样便出现了很多冗余布局,当它们之间需要交换业务时,直接把这些类的引用到处传递也是很头疼的事情,这时可用抽象了类来解决这个问题。当然,Fragement完全可以实现这样的功能,但也有它所不能施展的地方。
例:
有三个页面展示的类,为FirstUI、SecondUI、ThirdUI,它们所展示的页面分为三个部分,分别是标题栏,内容展示栏,底部状态栏,这时可将这三个部分抽取到抽象类中,在实现类里实现中间类型的动态加载以及对上下状态栏的数据刷新(这里没提取公共View,而是放到了各个管理器里了)。
代码如下:
抽象父类:
public abstract class BaseUI implements OnclicListener{
private Context context;
public BaseUI(Context context){
this.context = context;
}
//获取展示界面
public abstract View getChild();
//标识是哪一个界面
public abstract int getID();
@Override
public void onClick(View v) {
//并不是所有的界面都需要有点击事件,需要用到时,在复写这个方法
}
}
然后FirstUI类如下,其余不在鳌诉:
public class FirstUI extends BaseUI {
private Context context;
private TextView view;
public FirstUI(Context context) {
super(context);
this.context = context;
init();
}
public void init(){
view = new TextView(context);
LayoutParams params = view.getLayoutParams();
params = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
view.setLayoutParams(params);
view.setBackgroundColor(color.green);
view.setText("This is a first page!");
}
public View getChild() {
return view;
}
@Override
public int getID() {
// TODO Auto-generated method stub
return Constant.VIEW_FIRST; //建议将这个ID类型放在常量类中,便于统一管理
}
}
而在进行用户界面切换时,不需要给出具体实现类,可以采用字节码,而字节码
也不是任何类型都可以传递进来的,应该只能是BaseUI类的子类。
public void changeUI(Class<? extends BaseUI> targetClazz) {
String key = targetClazz.getSimpleName();//获取类名
if (viewAche.containsKey(key)) {
targetUI = viewAche.get(key);
} else {
try {
//得到他的构造器
Constructor<? extends BaseUI> constructor = targetClazz
.getConstructor(Context.class);
targetUI = constructor.newInstance(getContext());
viewAche.put(key, targetUI);
} catch (Exception e) {
throw new RuntimeException("BaseUI Constructor Error!");
}
}
}
2、当有多个容器各自管理着自己的任务,当某个容器内容变化后,与之相联系的容器也应当变化,传统的方式是在需要变化的容器内部进行更改,这样做之后会增大它们之间的耦合度,此时可以采用观察者模式进行解耦,当数据需要更改时,通知观察者改变数据。
具体做法,可以采用Java类库里的Observable类,也可以自己写一个这样的类(不建议哦!你对自己的编码能力是否有信心),继承它!
//继承已有工具类Observable
public class MiddleManager extends Observable {
private MiddleManager() {
}
}
private void change() {
// 观察者模式,改变监听状态,通知观察者数据改变了
this.setChanged();
//otherClass已注册的类的ID
this.notifyObservers(otherClass.getID());
}
添加观察的对象。
private void init() {
TitleManager manager = TitleManager.getInstance();
manager.init(this);
manager.showLoginTitle();
BottomManager bottom=BottomManager.getInstrance();
bottom.init(this);
bottom.showCommonBottom();
MiddleManager middle = MiddleManager.getInstance();
middle.setMiddle(ii_middle);
middle.changeUI(HallViewPager.class);
//观察者模式,添加观察者
middle.addObserver(manager);
middle.addObserver(bottom);
}
被观察者实现Observer接口,更新数据
//实现Obserever接口,实现Observer的方法
public class TitleManager implements Observer{
@Override
public void update(Observable observable, Object data) {
//干点坏事,别人都不知道
}
}
3、如果一个组件想要得到当前上下文,可以组件自身来获取。如下:
middle是一个Linearlayout,这样做可以防止当前上下文到处传递引用,避免造成内存泄漏。
public class ClassTemp{
//同过组件自身获得当前上下文
public Context getContext() {
return middle.getContext();
}
//通过view自己的父亲那里得到移除的方法,把自己干掉,就是自杀
public void init(LinearLayout view){
ViewGroup parent=(ViewGroup)view.getParent();
parent.removeView(view);
}
}
4、当使用LinearLayout布局时,发现(图.1)中的情况,这说明布局文件填充全部宽度没有起作用,导致的原因是root为空的时候,它不会设置LayoutParams。做法是自己去填充一下。代码如下:
showInMiddle = (LinearLayout) View.inflate(context, R.layout.il_hall1,
null);
if (showInMiddle.getLayoutParams() == null) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
showInMiddle.setLayoutParams(params);
}
图 1 手机界面未填充满效果图(盗图)
5、动态更改ListView的孩子,不影响已经加载的item。
首先为每一个item设置一个tag:
holder.iv_news.setTag(position);
得到要更新的组件:
TextView view = listview.findViewWithTag(position);
进行更新即可;
6、当在GridView中显示很多个相同的图片,而只是里面的文字不同,比如彩票的号码,他们的背景图片都一样,只是它们显示的文字不一样,那么我们可以用TextView来填充,不用将每张图片都画一遍,那样做的代价是很
大的,例子如下:
@Override
public int getCount() {
// TODO Auto-generated method stub
return endNum; //你要显示的球的个数
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
**TextView view = new TextView(context);
DecimalFormat decimalFormat = new DecimalFormat("00");
view.setText(decimalFormat.format(position + 1));
view.setBackgroundResource(R.drawable.id_defalut_ball);
view.setTextSize(16);
view.setGravity(Gravity.CENTER);**
return view ;
}
7、当有多个TextView要显示,并且颜色还不一样,可以用fromHtml进行转化,就不需要写那么的TextView了,例如:
定义数据:
<![CDATA[注数:  <font color="#ff0000">NUM</font>  注  金额:  <font color="#ff0000">MONEY</font>元]]>
String noticeInfo = context.getResources().getString(
R.string.is_shopping_list_notice);
noticeInfo = StringUtils.replaceEach(noticeInfo, new String[] { "NUM",
"MONEY" }, new String[] { lotterynumber.toString(),
lotteryvalue.toString() });
// Html.fromHtml(notice):将notice里面的内容转换
notice.setText(Html.fromHtml(noticeInfo));
8、当在做一个手机端程序,需要上传数据到网络,但又苦于用户可能没有网络,此时可以采用离线上传的做法。
首先,在本地数据库保存数据,用户每上传成功一条,你都要记录到本地数据库,已实现数据同步,但又要避免不断发送和接受重复数据,导致用户流量增加。此时,可以在设计数据库时设计两个表,一个是本地缓存表,一个是待上传的数据表,每上传成功一个就删去待上传数据表中的数据。这种做法如同冻结资金表。
9、项目使用的配置文件(bean.properties)必须跟随在src目录下。
10、图片中红色框里的东西代表,当把apk文件变为jar包的时候,让程序去自动管理资源文件的ID,不勾选会出现很蛋疼的问题(资源文件命名规则很重要)。
图2 eclispse创建工程界面
11、Android中点击图标不显示activity界面的办法,在清单文件里设置系统主题不显示界面(锁屏软件用得上哦)。
android:theme="@android:style/Theme.NoDisplay" />
12、建立杀不死的服务。这个有点狠,违背道德啊!仅供学习测试参考,开发人员慎用,出现后果自负,与本小编无关。
(1)进程守护
创建连个相同的服务,在
@Override
public void onDestroy() {}
方法里对另外一个服务启动,反过来相同,便可以达到目的
(2)广播接收者
用广播监听各种广播事件,当这个时间发生后,便会启动这个服务;
13、Android引用资源位图更改大小方法 。
//以Drawable取得资源里的图片
Drawable drawable = this.getResources().getDrawable(R.drawable.white);
//设置位图的大小与位置
drawable.setBounds(0, 0, pointSize, pointSize);
//创建一个内容为空的位图对象,这个位图对象在内存里是空的,并没有什么内容
Bitmap bitmap = Bitmap.createBitmap(pointSize, pointSize, Config.ARGB_8888);
//创建一个画布,将上面创建的位图画在这个画布上,此时这个画布也是空的,并没有什么东西
Canvas can = new Canvas(bitmap);
//调用Drawable自身的draw方法,将它自己画在刚才创建的额画布上
drawable.draw(can);
//最候,便可以得到自己想要多大并且可以在人员位置绘画的drawable资源里的图片
canvas.draw(bitmap,x,y,paint);
14、如何选择最佳存储选项。
(1)如果数据可以使用键/值对来标识,那么久使用SharedPreferences对象。
(2)如果需要存储临时数据,勇士内部存储器是一个很好的选择。
(3)有时需要和其他用户共享应用 程序数据,这时候可以将文件存储在设备上的SD卡上。
15、让文本框获得焦点,但不显示输入法面板。
<activity
android:name="com.example.autoui.MainActivity"
android:label="@string/app_name"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
16、使用Collections.sort(*,*)实现对数据的乱序处理。参数“T”代表你的数据类型,需要传入List对象。
Collections.sort(new ArrayList<T>(), new Comparator<T>() {
@Override
public int compare(T lhs, T rhs) {
//因为你永远无法知道它返回的是1还是-1,所以在比较时也无法
//知道谁大谁小,达到乱序的可能;
return Math.random() > 0.5 ? 1 : -1;
}
});
17、从图库(gallery)获取一张图片。
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
//获取image的uri
Uri imageFileUri = intent.getData();
//bmpFactoryOptions 图片的Options,直接加载到内存可能会OOM哦
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().
openInputStream(imageFileUri), null, bmpFactoryOptions);
18、获取图片文件获取Exif信息。
//从文件获取exif信息
ExifInterfaceei = new ExifInterface(imageFilePath);
String imageDescription = ei.getAttribute("ImageDescription");
if (imageDescription != null)
{
Log.v("EXIF", imageDescription);
}
//把exif信息写到文件:
ExifInterfaceei = new ExifInterface(imageFilePath);
ei.setAttribute("ImageDescription","Something New");
19、获取手机网卡mac地址,记得加权限。
//权限
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
private String getLocalMacAddress() {
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
return info.getMacAddress();
}
本人初出茅庐,文中难免有错误之处,还望指正,谢谢!