Android 常见问题解答

Panda-FAQ 同时被 2 个专栏收录
1 篇文章 0 订阅
69 篇文章 1 订阅

1、问题描述:
在存在多屏数据的时候,频繁滑动ListView会出现部分item黑屏的现象?

问题原因:
ListView的显示Adapter中的Item布局过于复杂,频繁滑动ListView时Android底层渲染不及时导致。

问题解决:
在AndroidMainnifest.xml中设置硬件加速,加速对界面渲染即可。(android:hardwareAccelerated=“true”)

2、问题描述:
webView在调用removeAllViews()的时候出现空指针异常:
java.lang.NullPointerException
android.webkit.WebViewClassic.sendViewSizeZoom(WebViewClassic.java:3573)

问题原因:
在AndroidMainifest.xml中的WebView的Activity设置了硬件加速。

问题解决:
针对当前Activity取消硬件加速即可。(android:hardwareAccelerated=“false”)
3、问题描述:
在更新新版本后,数据库报没有列名的异常?

问题原因:
用户升级版本夸大过大,而在判断的时候在onUpgrade方法中是根据oldVersion、newVersion来比较判断的,例如:用户从版本号为7直接升级到了版本号为9,此时为版本号为8的版本的字段则没有添加到数据库中。

问题解决:
在onUpgrade方法中对全部字段进行判断,判断方法为如果在数据库中不存在字段,则创建字段,例如:

// 直接在zg_message表中增加my_id列
private String ADD_MY_ID_CLUMN_TO_ZG_MESSAGE = "ALTER TABLE zg_message ADD my_id integer";

if (!DBHelperMethod.checkColumnExist(db,
				PandaDBConst.ZG_MESSAGE, "my_id")) {
			db.execSQL(ADD_MY_ID_CLUMN_TO_ZG_MESSAGE);
}

/**
	 * 检查某表列是否存在
	 * 
	 * @param db
	 * @param tableName
	 *            表名
	 * @param columnName
	 *            列名
	 * @return
	 */
	public static synchronized boolean checkColumnExist(SQLiteDatabase db,
			String tableName, String columnName) {
		boolean result = false;
		Cursor cursor = null;
		try {
			// 查询一行
			cursor = db.rawQuery("SELECT * FROM " + tableName + " LIMIT 0",
					null);
			result = cursor != null &&  cursor.getColumnIndex(columnName) != -1;
		} catch (Exception e) {
			Log.e(TAG, "checkColumnExists1..." + e.getMessage());
		} finally {
			if (null != cursor && !cursor.isClosed()) {
				cursor.close();
			}
		}

		return result;
	}
注意:我们再onCreate中创建表的时候也要判断表是否存在,然后再创建,例如:
// 频道动态表
db.execSQL("create table IF NOT EXISTS channel_dynamic(_id integer primary key,channelids varchar,content varchar)");

4、问题描述:
新闻类数据缓存有什么方案?

问题解决:
①当第一次进入界面首先读取缓存中的新闻数据(db或者sp中的数据),如果不存在则显示加载界面,如果存在则显示具体新闻。
②在显示的同时请求服务器获取最新的第一页数据,返回结果后然后更新界面,同时保存新闻数据到缓存中。
③当用户下拉刷新的是传入一个page字段,然后请求服务器,获取下一页的数据,page为你想要获取的数据的页数。
这样做如果有缓存数据,则用户每次进来都能看到数据的。

5、问题描述:
广告缓存有什么方案?

问题解决:
每次进入需要显示广告的界面,首先去缓存图片,如果图片缓存成功并且当前Activity没有销毁,则显示广告,反之不显示广告。

6、问题描述:
为什么从服务器上获取的图片已变形?

问题原因:
因为在xml中设置的是图片的background,因该设置图片的src(在代码中设置方法:setImageResouce(Bitmap bmp)),然后再设置图片的ScaleType为CenterCrop。

问题解决:
xml设置:android:scaleType=“centerCrop”;
代码设置:iv.setScaleType(ScaleType.CENTER_CROP);

7、问题描述:
耗时请求后(AsyncTask)更新界面异常:is your activity running?

问题原因:
因为Activity已经销毁,但是没有取消AsyncTask,当异步执行完毕后,更新界面发现界面以及销毁,如果在这个时候弹出Dialog则会出现这个错误。

问题解决:
在弹出Dialog前面判断:

if(mContext != null && !((Activity)mContext).isFinishing()){
                  MyAlertDialog();
			         .........
}

8、问题描述:
Android中EditText获取焦点键盘弹出来后将整个布局都顶了上去,怎么设置只顶EditText,不顶整个布局?

问题解决:
把不需要顶上去的布局最外层包裹一层ScrollView。

9、问题描述:
Android属性动画不重复执行问题?

问题解决:
ObjectAnimator oa ;
… …
oa.setRepeatCount(ObjectAnimator.INFINITE);

10、问题描述:
Android中点击Back键盘退出APP报错:IllegalStateException: Can not perform this action after onSaveInstanceState。(从日志中可以看出是在fragment.commit()方法中出的错)。

问题原因:
在使用commit方法是在Activity的onSaveInstanceState()之后调用的,这样会出错,因为onSaveInstanceState方法是在该Activity即将被销毁前调用,来保存Activity数据的,如果在保存玩状态后再给它添加Fragment就会出错。

问题解决:
把commit()方法替换成commitAllowingStateLoss()就行了,其效果是一样的。

11、问题描述:
通过ImageSpan设置ImageView大小失效问题(通过TextView高度设置图片高度,从而使得图片随着文字大小改变而改变).

问题原因:
在构造ImageSpan时候使用了默认的一个参数的构造方法造成的。(使用的是默认mTargetDensity密度,所以我们即使设置了大小但是还是不管用的)

问题解决:
使用ImageSpan带两个参数(带有Context)的构造方法即可。

12、问题描述:
在Android中如何设置TextView上下文字滚动?

问题解决:
布局中和代码中分别设置相应
①布局属性设置:

android:scrollbarFadeDuration="5000"
android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical"
android:singleLine="false"

例如:

 <TextView
      android:id="@+id/id_msg_tv"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:maxHeight="100dip"
      android:minHeight="40dip"
      android:layout_margin="10dp"
      android:background="#FFF"
      android:padding="10dp"
      android:scrollbarFadeDuration="5000"
      android:scrollbarStyle="outsideOverlay"
      android:scrollbars="vertical"
      android:singleLine="false"
      android:textColor="#000"/>

②代码属性设置:

TextView id_msg_tv = (TextView) contentView.findViewById(R.id.id_msg_tv);
id_msg_tv.setMovementMethod(ScrollingMovementMethod.getInstance()); 

12、问题描述:
在Android中Activity背景默认为啥是黑色的?

问题原因:
在代码中或者Androidmainfest.xml中设置了主题样式为黑色的导致的。

问题解决:

二、在java文件里设置:

LinearLayout myLayout = () findViewById(R.id.linearLayout1);
myLayout.setBackgroundColor(Color.WHITE);
三、在AndroidManifest.xml里利用android:theme来设置,这个命令还是很强大的,如下所示:
theme的设置 可以设置为系统自带的格式,也可以自定义格式。
 
A: 系统自带格式
 
   @android:style/Theme.Black  //背景黑色-有标题-非全屏
   @android:style/Theme.Black.NoTitleBar //背景黑色-无标题-非全屏
   @android:style/Theme.Black.NoTitleBar.Fullscreen //背景黑色-无标题-全屏显示
   @android:style/Theme.Dialog //对话框显示
   @android:style/Theme.InputMethod
 
   @android:style/Theme.Light    //背景白色-有标题-非全屏
   @android:style/Theme.Light.NoTitleBar //背景白色-无标题-非全屏
   @android:style/Theme.Light.NoTitleBar.Fullscreen //背景白色-无标题-全屏显示
 
   @android:style/Theme.Light.Panel
   @android:style/Theme.Light.WallpaperSettings //背景透明
   @android:style/Theme.NoDisplay
 
   @android:style/Theme.Translucent.NoTitleBar.Fullscreen //半透明、无标题栏、全屏
 
   @android:style/Theme.Wallpaper.NoTitleBar.Fullscreen
 
可以在单个Activity里设置,也可以在applicaiton里全局设置。比如:
 
<activity android:screenOrientation="portrait" android:name=".ui.RegisterActivity" android:theme="@android:style/Theme.NoTitleBar"></activity>

13、问题描述:
ava.util.ConcurrentModificationException
java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
com.diipo.traffic.punish.BindDrivingLicenceActivity$5.onClick(BindDrivingLicenceActivity.java:319)
问题原因:
对Vector、ArrayList在迭代的时候如果同时对其进行修改就会抛出java.util.ConcurrentModificationException异常

for(CarInfo info : phoneSelectList){								
	if(!info.getCar_phone().equals(driver_phone)){
		CarInfo ifo = new CarInfo();	
		ifo.setCar_phone(driver_phone);								      
		phoneSelectList.add(ifo);
	}
}

问题解决:

ArrayList<CarInfo> phoneSelectListBack = new ArrayList<CarInfo>();
for(CarInfo info : phoneSelectList){								
	if(!info.getCar_phone().equals(driver_phone)){
		CarInfo ifo = new CarInfo();	
		ifo.setCar_phone(driver_phone);								      
		//phoneSelectList.add(ifo);
		phoneSelectListBack.add(infoBack);
	}
}

for(CarInfo infoBack : phoneSelectListBack){
	phoneSelectList.add(infoBack);
}

14、问题描述:
怎样给ListView设置EmptyView?

解决办法:
自定义emptyView:
reload_layout.xml

<?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:orientation="vertical"
    android:gravity="center"
    >
    
    <TextView 
    android:id="@+id/loadText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:drawablePadding="10dip"
    android:drawableTop="@drawable/ic_reload"
    android:gravity="center"
    android:text="没有数据,点击屏幕刷新"
    android:textColor="@color/gray_text"
    android:textSize="@dimen/font_normal"
    android:visibility="visible" />
</LinearLayout>

在代码中添加:

View emptyView = LayoutInflater.from(getActivity()).inflate(R.layout.reload_layout, null);  
emptyView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); 
emptyView.setVisibility(View.GONE);//注意这行代码
((ViewGroup)mListView.getParent()).addView(emptyView);//注意这行代码
mListView.setEmptyView(emptyView);

按照以上代码添加即可完成Empty的设置。

15、问题描述
布局中键盘弹出来将ListView的内容盖住了,我们想将ListView内容顶上去需要怎么做?

问题原因:
是transcriptmode属性默认为disabled造成的。我们可以在AbsListView的源代码中可以看出:

	/**
     * Disables the transcript mode.
     *
     * @see #setTranscriptMode(int)
     */
    public static final int TRANSCRIPT_MODE_DISABLED = 0;
    /**
     * The list will automatically scroll to the bottom when a data set change
     * notification is received and only if the last item is already visible
     * on screen.
     *
     * @see #setTranscriptMode(int)
     */
    public static final int TRANSCRIPT_MODE_NORMAL = 1;
    /**
     * The list will automatically scroll to the bottom, no matter what items
     * are currently visible.
     *
     * @see #setTranscriptMode(int)
     */
    public static final int TRANSCRIPT_MODE_ALWAYS_SCROLL = 2;

//重点是下面代码
int transcriptMode = a.getInt(R.styleable.AbsListView_transcriptMode,
                TRANSCRIPT_MODE_DISABLED);
        setTranscriptMode(transcriptMode);

备注:transcriptmode三个属性值的作用上面已经有解释了:
disabled:禁用模式,禁止滚动,所以键盘将ListView顶部上去。
normal:正常(标准)的模式,键盘可以将ListView中的内容顶上去。
always_scroll:键盘弹出来的时候,ListView列表会自定滚动到底部。

问题解决:
设置transcriptmode属性normal即可。

16、转义字符问题:

//错误做法:
String s = "/mnt/sdcard/im/pic/1001.jpg|/mnt/sdcard/im/pic/1002.jpg";
String str[] = s.split("|");

//正确做法
String s = "/mnt/sdcard/im/pic/1001.jpg|/mnt/sdcard/im/pic/1002.jpg";
String str[] = s.split("\\|");

问题原因:"\\会转义"","\|“才代表的”|"的意思。

17、问题描述:
我在ActivityA中跳转到ActivityB中,会调用ActivityA的onActivityResult方法,而且ActivityB中setResult后ActivityA为什么不会回调onActivityResult方法?

问题原因:
LauncherMode对Activity的onActivityResult的影响。

stackoverflow上有些人跟我遇到的问题类似。比如说有一位开发者把Activity设置成了singleTask模式,onActivityResult就收不到任何结果了。当他把singleTask模式改回标准模式,又恢复正常。

这个问题下面给出的答案中,有一位说startActivityForResult的文档中有这么一句话:

For example, if the activity you are launching uses the singleTask launch mode, it will not run in your task and thus you will immediately receive a cancel result.

意思是:比如说,如果你正加载的activity使用了singleTask的加载模式,它不会在你的栈中运行,而且这样你会马上收到一个取消的结果。

即在onActivityResult里马上得到一个RESULT_CANCEL.

他还补充说没有很好的补救方法。可以试试用监听广播的方法。

另一个stackoverflow的问题中,有人直接回答了不能再singleInstance或singleTop模式下使用startActivityForResult()方法,不仅被采纳了,票数还不低。

剩下的一个stackoverflow问题中,有人说把singleTask改成singleTop就会正常,得到高达59票并被采纳。实际上我用的就是singTop,可是onActivityResult还是无缘无故被调用了。
原文链接:http://www.cnblogs.com/tt_mc/p/3586834.html

问题解决:

以后在选择Activity的加载模式时,要考虑onActivtyResult方法与之存在冲突。

18、问题描述:
使用AsyncTask的时候报:java.lang.NoSuchFieldError android.os.AsyncTask.THREAD_POOL_EXECUTOR.

问题原因:Android手机版本号低于11以后会出现兼容“THREAD_POOL_EXECUTOR”问题。

问题解决:

import android.annotation.TargetApi;
import android.os.AsyncTask;
import android.os.Build;

public class AsyncTaskUtils {

	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	public static void executeOnExecutor(AsyncTask<String, Void, String> task) {
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
			task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
		} else {
			task.execute();
		}
	}

}

19、问题描述:
在使用Fragment的时候出现异常:java.lang.InstantiationException
can’t instantiate class com.diipo.traffic.punish.refactor.MyDrivingLicenceFragment; no empty constructor。

问题原因:
当系统因为内存紧张杀死非前台进程(并非真正的杀死),然后我们将被系统杀掉的非前台app带回前台,如果这个时候有UI是呈现在Fragment中,那么会因为restore造成fragment需要通过反射实例对象,从而将之前save的状态还原,而这个反射实例对象就是fragment需要Public的empty constructor的关键所在。

参考:http://blog.csdn.net/xplee0576/article/details/43057633

问题解决:
添加一个参数为空的构造函数即可。

20、问题描述:
从Fragment界面跳转到相机或者频繁切换到地图Fragment会出现异常:java.lang.IllegalArgumentException
Binary XML file line #14: Duplicate id 0x7f0c0583, tag null, or parent id 0x0 with another fragment for com.amap.api.maps.TextureSupportMapFragment。

问题原因:
Fragment还有一个子TextureSupportMapFragment没有被删除,第二次加载因为重复报错(切换相机或者频繁切换Fragment会耗用大量内存,Android系统可能会回收到当前Fragment所在的Activity和Fragment,造成不会执行Fragment的onDestory,然后没有从地图界面移除TextureSupportMapFragment,然后在重新回到界面会重新加载Fragment,重新执行Fragment的onCreate来重新填充布局)。

问题解决:将xml中fragment替换为FrameLayout,然后再代码中替换即可。

            
            <FrameLayout
                android:id="@+id/map"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
<!--             <fragment
                android:id="@+id/map"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                class="com.amap.api.maps.TextureSupportMapFragment" /> -->

java代码中:

private void initMapView(Bundle savedInstanceState, View view) {
//		TextureSupportMapFragment textureSupportMapFragment = ((TextureSupportMapFragment) getFragmentManager()
//				.findFragmentById(R.id.map));
//		aMap = textureSupportMapFragment.getMap();
		
		TextureSupportMapFragment textureSupportMapFragment = TextureSupportMapFragment.newInstance();
		FragmentManager fm = getChildFragmentManager();
		fm.beginTransaction().replace(R.id.map, textureSupportMapFragment).commit();
		try {
			MapsInitializer.initialize(context);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		aMap = textureSupportMapFragment.getMap();
		
		setUpMap();
		setAnimateCamera();
		aMap.setTrafficEnabled(true);// 显示实时交通状况
		aMap.setOnCameraChangeListener(this);
	}

记得在onDestory中销毁fragment:

/**
	 * 解决Fragment中嵌套高地地图Framgment问题
	 */
	private void removeMap() {
		try {
			FragmentManager fm = getActivity().getSupportFragmentManager();
			TextureSupportMapFragment fragment = (TextureSupportMapFragment) (fm
					.findFragmentById(R.id.map));
			FragmentTransaction ft = fm.beginTransaction();
			if (fragment != null) {
				ft.remove(fragment);
				ft.commitAllowingStateLoss();
			}
			if (aMap != null) {
				aMap.setMyLocationEnabled(false);
				L.d(TAG, "--->>>remove aMap");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

21、问题描述:
从弹幕发送过快的解决方案中提取出对象复用原理(类似于ListView的复用原理):
①可以建一个队列A和队列B。
②然后每次接收到弹幕的时候添加到队列A。
③然后循环遍历队列B,如果队列B中有数据,则取出来并且重新赋值,如果没有则New对象并且添加队列B中。
这样可以保证队列B中只有一屏的对象个数,不会造成内存爆棚的情况。

22、资源地址:
数据库学习资源库:

http://www.w3school.com.cn/sql/sql_update.asp

23、问题描述:
Android通过Sdcard安装Apk,安装完成后点击打开->进入程序主界面->按下Home键->再次通过Launcher点击应用图标->有打开了一个主界面。

问题原因/问题解决:
http://www.2cto.com/kf/201407/319948.html。

24、问题描述:
为什么webview点击goback的时候没调用onReceiverTitle(String title)?
(发现在小米3或个别的手机上,当通过webview.goBack()回退的时候,并没有触发onReceiveTitle(),这样会导致标题仍然是之前子页面的标题,没有切换回来.)

问题原因:
具体问题原因不是很清楚。

问题解决:
正常顺序加载的情况onReceiveTitle是一定会触发的,所以就需要自己来维护webview url与title的映射关系
那么就需要一个HashMap保存url及对应的title.
正常顺序加载时,将url和对应的title保存起来,webview回退时,,找到对应的title进行设置即可。

维护webview url与title的栈:

public class WebViewTitleStack {

	public static  HashMap<String, String> stacks = new HashMap<String, String>();
	
	
	public static void add(String url,String title){
			for(String loadUrl : stacks.keySet()){
			if(loadUrl.equals(url)){
				return;
			}
		}
		stacks.put(url, title);
	}
	
	public static String getTitle(String url){
		for(String loadUrl : stacks.keySet()){
			if(loadUrl.equals(url)){
				return stacks.get(loadUrl);
			}
		}
		return null;
	}
	
	public static void clean(){
		stacks.clear();
	}
}

正常情况下,往栈中添加和使用Eventbus来显示title:

@Override
public void onReceivedTitle(WebView view, String title) {
			super.onReceivedTitle(view, title);
			String url = view.getUrl();
			WebViewTitleStack.add(url, view.getTitle());
			setTitleOperation(view, url);
			L.d(TAG, "--->>>onReceivedTitle:"+title+",url:"+url);
		}
public static void setTitleOperation(WebView view, String url) {
		String title = WebViewTitleStack.getTitle(url);
		
		//用EventBus来解耦
		if(!TextUtils.isEmpty(title)){
			EventBus.getDefault().post(title);
		}
		L.d(TAG, "--->>>title onPageFinished:"+title+",webView.getTitle:"+view.getTitle());
	}

特殊情况下,webview点击goback()不调用onReceiverTitle()时,通过onPageFinished()来获取title,然后通过Eventbus来显示title:

@Override
public void onPageFinished(WebView view, String url) {
				super.onPageFinished(view, url);
				ProgressWebView.setTitleOperation(view, url);
			}

页面销毁的时候清除栈中数据:

protected void onDestroy() {
	super.onDestroy();
	EventBus.getDefault().unregister(this);
	L.d("", "--->>>removeWebView onDestroy");
}

参考:http://blog.csdn.net/t12x3456/article/details/13769731

25、问题描述:
ListView的getview调用次数多于子view个数的问题?

问题原因:
listview的高度设置成wrap_content,这样做的问题在于,ListView没有取到实际的高度,他还要根据计算才能确定,而每一次计算应该会触发listview的渲染,所以就会出现getview的调用次数跟正常情况相比多了好几倍。

问题解决:
①把listiview在布局文件中的高度总是设置为:fill_parent(或者match_parent)。
②动态设置ListView高度:

/**
 * 解决ListView中getView不断调用问题
 * @param id_common_auto_lv
 */
	private void fixationListViewHeight(AutoReFreshListView id_common_auto_lv) {
		ViewGroup.LayoutParams params = id_common_auto_lv.getLayoutParams();
		params.height = AndroidUtil.getScreenHeight(context);
		id_common_auto_lv.setLayoutParams(params);
	}

26、问题描述:
在往ViewGroup中添加view的时候报异常:The specified child already has a parent. You must call removeView() on the child’s parent first。

问题原因:
假设LayoutA中有一个TextView,然后想将TextView添加进入LayoutB中,会报这个错,原因是TextView已经是LayoutA的孩子了,如果再添加进入LayoutB就会报这个错误。

问题解决:
将TextView为从LayoutA中移除,然后再添加到LayoutB中即可。

layoutA.removeView(textView);//接触textView与layoutA的关系
layoutB.addView(textView);//将textView添加进入layoutB。

27、问题描述:
ViewGroup无限滑动问题,从最后一张跳转到第一张会出现切换不顺畅问题,从最后一个界面切换到第一个界面会经过多个View,会闪一下。

解决方案:
步骤:
①多创建两个View(data.size() + 2),第一个view显示最后一个item的数据,最后一个显示第一个item的数据。
②当用户滑动到最后一个界面的时候(最后一个界面就是第一个item的数据),切换到position=1(真实的第一个item位置)的位置上即可。

//从最后一个界面切换到第一个界面的实例代码
private int resetCurrentPosition(int currentPosition) {
		if(currentPosition == datas.size() + 1){
			currentPosition = 1;
		}
		return currentPosition;
}

③同理,当用户滑动到第一个界面的时候,切换到position=data.size()(真实的最后一个item的位置)即可。

28、问题描述:
ViewPager的notifyDataSetChange()无效?

问题原因:
参考:http://www.cnblogs.com/maoyu417/p/3740209.html

问题解决:
覆盖getItemPosition()方法,当调用notifyDataSetChanged时,让getItemPosition方法人为的返回POSITION_NONE,从而达到强迫viewpager重绘所有item的目的。

29、问题描述:
ScrollView中嵌套ListView的时候,出现ListView只能显示一行的问题。

问题原因:
ScrollView嵌套ListView的时候,使得ListView无法计算出高度。

问题解决:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); 
		super.onMeasure(widthMeasureSpec, expandSpec);
}

30、问题描述:
java.lang.ClassCastException: android.widget.RelativeLayout L a y o u t P a r a m s c a n n o t b e c a s t t o a n d r o i d . w i d g e t . L i n e a r L a y o u t LayoutParams cannot be cast to android.widget.LinearLayout LayoutParamscannotbecasttoandroid.widget.LinearLayoutLayoutParams。

问题原因:
类型转化异常,不能设置成当前的布局的params.
问题解决:
需要设置成父layout的params。
http://m.blog.csdn.net/article/details?id=41047157
http://www.iteye.com/problems/93608

31.问题描述:
references org.chromium.android_webview.AwContents.mContainerView.

问题原因:
原生webview内存泄露。

问题解决:
给webview重新开一个进程,退出的时候System.exit(0)来解决webview原生的泄露问题。
http://my.oschina.net/zhibuji/blog/100580

32.问题描述:
昨天修改manifest 文件中activity 的 模式为单例模式:Android:launchMode=“singleTask” ,发现我的onActivityResult 无法触发了,后来修改回来又可以触发了。

问题原因:
如果activity在manifest里面设置为singleInstance了,那么这个方法就无效了!

33.问题描述:
AsyncTask内存泄露解决:
http://blog.csdn.net/womengmengyan/article/details/52315564

34.问题描述:
activity中dialog.show(),后无法显示dialog。

问题原因:
此处的context 要保证你的上下文要为activity对象,只有activity才能添加ProgressDialog窗体,
为了确保正确,context可以使用activity.this表示,不要一味地写成getApplicationContext()。

问题解决:
context改为传入的activity的context(XXXActivity.this))。

35.问题描述:
webview加上放大缩小后发现点击返回报错。
点击返回执行代码:

if (webView != null) {
		webView.setVisibility(View.GONE);
		webView.removeAllViews();
		webView.destroy();
}

webview设置代码:

private static void setWebViewCommonSetting(WebView webView) {
		/***打开本地缓存提供JS调用**/
		webView.getSettings().setDomStorageEnabled(true);

		setNoZoom(true,webView);

		//设置允许webview和javascript交互
		webView.getSettings().setJavaScriptEnabled(true);
		webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
		webView.getSettings().setAllowFileAccess(true);

		//支付宝不能支付问题
		CookieManager.getInstance().setAcceptCookie(true);
	}

	private static void setNoZoom(boolean isZoom,WebView webView) {
		webView.getSettings().setBuiltInZoomControls(isZoom);
		webView.getSettings().setSupportZoom(isZoom);
		webView.getSettings().setDisplayZoomControls(isZoom);
	}

错误原因:
webview放大缩小底层不兼容问题。

问题解决:
屏蔽掉放大缩小按钮即可:

webView.getSettings().setDisplayZoomControls(false);

36.问题描述
Android Application的onCreate多次启动问题。

问题原因:多进程问题,加一个判断就可以了。

问题解决:

@Override
    public void onCreate() {
        super.onCreate();
        String processName = getProcessName(this);
        if (processName!= null) {
            if(processName.equals("com.soubw.prodemo")){
                //初始化com.soubw.prodemo以包名为进程名,项目默认的进程
            } else if(processName.equals("com.soubw.prodemo:login")){
                //初始化com.soubw.prodemo:login
            }else if(processName.equals("com.wxj.register")){
                //初始化com.wxj.register
            }else{

            }
        }
    }


    private String getProcessName(Context context) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
        if (runningApps == null) {
            return null;
        }
        for (ActivityManager.RunningAppProcessInfo proInfo : runningApps) {
            if (proInfo.pid == android.os.Process.myPid()) {
                if (proInfo.processName != null) {
                    return proInfo.processName;
                }
            }
        }
        return null;
    }

http://blog.csdn.net/wx_jin/article/details/50894058

37.问题描述:
Android Studio编译成功后点击App保错:java.lang.IllegalArgumentException: Service Intent must be explicit: Intent。

问题原因:
在Activity中启动Service的时候报错: 服务意图必须是显性声明。 这是为了防止造成冲突(i.e. 有多个Service用同样的intent-filter的情况)

这是Android 5.0 (Lollipop) 之后的规定。 不能用包名的方式定义Service Intent, 而要用显性声明:

问题解决:
将build.gradle中的targetSdkVersion改成5.0以下的对应值,比如18。

http://www.cnblogs.com/yidan621/p/5667299.html

38.问题描述:
Android Studio编译成功后点击App保错:java.lang.NoClassDefFoundError: com.diiji.traffic.WelcomeToDeYang$CityAsyncTask$2”;其实工程中是有对应的类的,就是报这个错误。

问题原因:
应该超过64K了,设置了分(multiDexEnabled true),但是没有使当前的应用继承MultiDexApplication,导致没有合并dex包,导致找不到类的class文件。

问题解决:
是当前应用的Application继承MultiDexApplication即可。

39.问题描述
FastJson解析错误:create instance error, class com.dj.zigonglanternfestival.info.MyVioceChannelListEntity$LBEntity

错误原因:
FastJson不支持这个写法。

问题解决:

B嵌套在A里,那么我们要声明内嵌类static属性,如下(这样问题解决)

public class  A{

          private String haha;

          private  int   gogo;

          private B   bb;

set和get方法省略。。。。。


         publicstatic class B{

          private String name;

          private  int   price;

set和get方法省略。。。。。
              }

}

40.问题描述:
fastjson解析成map时候的异常。

问题解决:

//正确写法
HashMap<String,String> maps = (HashMap<String, String>)JSON.parseObject(channelMessageStr, new TypeReference<Map<String, String>>() {});
//错误写法
//HashMap<String,String> maps = (HashMap<String, String>) JSON.parse(channelMessageStr);

参考:http://blog.csdn.net/lanxingfeifei/article/details/49154845

40.问题描述:
数据库倒叙分页查询问题。
查询最后一条数据 (第一次查询)

select * from messages_box order by id desc limit 2

查询最后一条数据 (第二次查询)

select * from messages_box where id<id order by id desc limit 2

这个id是上一次查询出来的最后一条的id。

41.问题描述:
三星手机拍照重新调用了onCreate方法和onConfigurationChanged,导致系统崩溃。

问题解决:
1.再AndroidManifest.xml中配置调用手机拍照的activity的属性,最重要是configChanges属性。

android:configChanges="orientation|screenSize|keyboardHidden|navigation"
android:windowSoftInputMode="adjustResize"
android:screenOrientation="portrait"

2.在调用手机拍照的activity中重载onConfigurationChanged方法,这个很关键,否则上面设置了属性也不管用。

public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
}

转载:http://blog.csdn.net/jjmm2009/article/details/72457718。

42.问题描述:
android 部分(三星)手机拍照后照片旋转问题解决方案.
1、读取图片的旋转属性.

/**
 * 读取图片的旋转的角度
 *
 * @param path
 *            图片绝对路径
 * @return 图片的旋转角度
 */
private int getBitmapDegree(String path) {
    int degree = 0;
    try {
        // 从指定路径下读取图片,并获取其EXIF信息
        ExifInterface exifInterface = new ExifInterface(path);
        // 获取图片的旋转信息
        int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL);
        switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            degree = 90;
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            degree = 180;
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            degree = 270;
            break;
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return degree;
}

2、将图片按照某个角度进行旋转

/**
 * 将图片按照某个角度进行旋转
 *
 * @param bm
 *            需要旋转的图片
 * @param degree
 *            旋转角度
 * @return 旋转后的图片
 */
public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
    Bitmap returnBm = null;
  
    // 根据旋转角度,生成旋转矩阵
    Matrix matrix = new Matrix();
    matrix.postRotate(degree);
    try {
        // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
        returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
    } catch (OutOfMemoryError e) {
    }
    if (returnBm == null) {
        returnBm = bm;
    }
    if (bm != returnBm) {
        bm.recycle();
    }
    return returnBm;
}

43.问题描述:
Android性能分析文章:
工匠若水:http://blog.csdn.net/yanbober/article/details/48394201

44.问题描述:
如何计算图片对占用内存的大小:

一张图片到底占用多少内存呢?
  图片占用内存的计算公式:图片高度 * 图片宽度 * 一个像素占用的内存大小
  假设我们的图片放到xhdpi目录下,那么我们本文中的图片占用的内存大小如下:
  屏幕密度为2的设备:800 * 600 * 4byte = 1.83M
  屏幕密度为3的设备:800 * 1.5 * 600 * 1.5 * 4byte = 1.83 * 2.25M = 4.12M
  所以,计算图片占用内存大小的时候,要考虑图片所在的目录跟设备密度,这两个因素其实影响的是图片的高宽,android会对图片进行拉升跟压缩。
  
一个像素为什么是占用4个字节呢!
关于ARGB_8888、ALPHA_8、ARGB_4444、RGB_565的理解
A:透明度
R:红色
G:绿
B:蓝
Bitmap.Config ARGB_4444:每个像素占四位,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位
Bitmap.Config ARGB_8888:每个像素占四位,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位
Bitmap.Config RGB_565:每个像素占四位,即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位
Bitmap.Config ALPHA_8:每个像素占四位,只有透明度,没有颜色。
一般情况下我们都是使用的ARGB_8888,由此可知它是最占内存的,因为一个像素占32位,8位=1字节,所以一个像素占4字节的内存。假设有一张480x800的图片,如果格式为ARGB_8888,那么将会占用1500KB的内存.

优化:
BitmapFactory.Options options = new BitmapFactory.Options();
// options.inSampleSize = 3; // 原图的五分之一,设置为2则为二分之一
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), bgImg, options);
runImage.setImageBitmap(bitmap);

参考:
http://www.cnblogs.com/popfisher/p/6959106.html
http://www.cnblogs.com/popfisher/p/6770018.html
http://www.cnblogs.com/popfisher/p/6770018.html

45.问题描述:
fragmentAdapter+viewPager,添加或者删除fragment后还是之前的fragment问题。

问题原因:
①fragment移除失败:
解决:重新getItemId,将每一个fragment的唯一id返回回去即可。
②已经添加过的fragment,过来后再添加后发现白屏:
解决:从新调用了oncreateView,判断存在布局将其移除即可.
参考:http://blog.csdn.net/u014452224/article/details/45920315

46.问题描述:
textView文字选择器怎么定义?

问题解决:
①xml中selector:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="true" android:color="@color/title_color"/>
    <item android:state_enabled="false" android:color="#000000"/>
    <item android:color="#000000"/>
</selector>

②布局中代码:

<TextView
      android:id="@+id/id_common_top_tv"
      android:layout_width="0dip"
      android:layout_height="fill_parent"
      android:layout_centerInParent="true"
      android:layout_weight="1"
      android:enabled="false"
      android:gravity="center"
      android:paddingLeft="2dip"
      android:text="未阅"
      android:textColor="@color/tv_color_selector" />

③.java文件设置:

id_common_top_ll.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        setTextViewEnable(id_common_top_tv);
                    }
                });

private void setTextViewEnable(TextView id_common_top_tv) {
        for (TextView textView : textViews) {
            if (textView.getText().toString().equals(id_common_top_tv.getText().toString())) {
                textView.setEnabled(true);
            } else {
                textView.setEnabled(false);
            }
        }
    }

47.问题描述:
Android Dialog设置TYPE_SYSTEM_ALERT 有些手机不能显示问题。

问题原因:

mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

但是某些手机对底层进行了修改(小米,魅族之类),系统会默认会拒绝该权限。

问题解决:
通过将type设定为TYPE_TOAST, 就可以绕过检查

mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);  

参考:http://592713711.iteye.com/blog/2316150

48.问题描述:
华为带有底部导航栏的手机屏幕高度获取为什么会变化?

问题原因:
通过这个方法获取的高度,底部导航栏不包含在屏幕高度之中:

/**
 * 获得屏幕高度
 * @param context
 * @return
 */
public static int getScreenHeight(Context context) {
   WindowManager wm = (WindowManager) context
         .getSystemService(Context.WINDOW_SERVICE);
   
   int height = wm.getDefaultDisplay().getHeight();// 屏幕高度
   return height;
}

本来高度:1920
显示底部状态栏后的高度为:1812

当底部状态栏影藏的时候这个时候再回去屏幕高度又会发生变化,变成了1920。

这里就延申了一个问题,如果要设置屏幕的View的宽高,那么就要判断:是否有底部导航栏,然后底部导航栏是否变换了,如果底部导航栏变化了则重新设置高度。

demo:


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
		Bundle savedInstanceState) {
	L.d(TAG, "--->>>getSimpleName1:"+this.getClass().getName());
	fatherView = inflater.inflate(R.layout.base_fragment_title, container, false);

	lastIsShow = AndroidUtil.isNavigationBarShow(context);
	return fatherView;
}

id_ydy_rl.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
			@Override
			public void onGlobalLayout() {
				boolean isShow = isNavigationBarShow(context);
				if(isShow != lastIsShow){
					L.i(TAG,"--->>>onGlobalLayout isShow:"+isShow);
					setGuideImagVieWidthAndHeight(ydyView);
				}
				lastIsShow = isShow;
			}
		});
private void setGuideImagVieWidthAndHeight(View ydyView) {
		final ImageView id_traffic_guide_iv = (ImageView) ydyView.findViewById(R.id.id_traffic_guide_iv);
		ViewGroup.LayoutParams ivParams = id_traffic_guide_iv.getLayoutParams();
		ivParams.width = AndroidUtil.getScreenWidth(context);
		ivParams.height = AndroidUtil.getActivityHeight(context);
		id_traffic_guide_iv.setLayoutParams(ivParams);
	}

/**
	 * 检查虚拟按键栏是否显示
	 *
	 * @param context
	 * @return
	 */
	public static boolean isNavigationBarShow(Context context){
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
			Display display = ((Activity)context).getWindowManager().getDefaultDisplay();
			Point size = new Point();
			Point realSize = new Point();
			display.getSize(size);
			display.getRealSize(realSize);
			return realSize.y!=size.y;
		}else {
			boolean menu = ViewConfiguration.get(context).hasPermanentMenuKey();
			boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
			if(menu || back) {
				return false;
			}else {
				return true;
			}
		}
	}

49.问题描述:
APP的引导页逻辑:
判断是否第一次打开应用程序:

/**
	 * 判断是否第一次打开应用程序
	 * 
	 * @return true 是第一次 反之不是
	 */
	public static boolean isFirstOpenApp(Context ctx) {
		// 是否是第一个打开,默认为true
		boolean isFirstOpenApp = SharedPreferencesUtil.getBoolean(ConfigInfo.PREF_IS_FIRST_OPEN_APP, true);
		int currentVerCode = getVerCode(ctx, "com.traffic.panda");
		int verCode = SharedPreferencesUtil.getInt(ConfigInfo.VER_CODE,0);
		L.i(TAG,"--->>>isFirstOpenApp currentVerCode:"+currentVerCode+",verCode:"+verCode+",isFirstOpenApp:"+isFirstOpenApp);
		if (isFirstOpenApp || (currentVerCode > verCode && ZiGongConfig.IS_CHANGE_GUIDANCE_PAGE)) {
			return true;
		}
		return false;
	}

显示完引导页后调用的方法:

/**
	 * 保存第一次打开应用程序的参数
	 */
	public static void saveOpenAppParement(Context context) {
		SharedPreferencesUtil.saveBoolean(ConfigInfo.PREF_IS_FIRST_OPEN_APP, false);
		int verCode = getVerCode(context, "com.traffic.panda");
		L.i(TAG,"--->>>saveOpenAppParement verCode:"+verCode);
		SharedPreferencesUtil.saveInt(ConfigInfo.VER_CODE, verCode);
	}

常量:

//如果引导图有变则将IS_CHANGE_GUIDANCE_PAGE设置成true,否则设置成false
	public static final boolean IS_CHANGE_GUIDANCE_PAGE = true;

50.问题描述:
Buttton设置成
android:layout_width="wrap_content" android:layout_height="wrap_content"
后发现有默认的高度。

问题原因:
开了button源码:

* {@link android.R.styleable#View View Attributes}
 * </p>
 */
@RemoteView
public class Button extends TextView {
    public Button(Context context) {
        this(context, null);
    }

    public Button(Context context, AttributeSet attrs) {
        this(context, attrs, com.android.internal.R.attr.buttonStyle);
    }

    public Button(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public Button(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public CharSequence getAccessibilityClassName() {
        return Button.class.getName();
    }
}

看到button默认的样式:

com.android.internal.R.attr.buttonStyle

源码:

<style name="Widget.Toolbar">
        <item name="titleTextAppearance">@style/TextAppearance.Widget.Toolbar.Title</item>
        <item name="subtitleTextAppearance">@style/TextAppearance.Widget.Toolbar.Subtitle</item>
        <item name="minHeight">?attr/actionBarSize</item>
        <item name="titleMargin">4dp</item>
        <item name="maxButtonHeight">@dimen/action_bar_default_height_material</item>
        <item name="buttonGravity">top</item>
        <item name="navigationButtonStyle">@style/Widget.Toolbar.Button.Navigation</item>
        <item name="collapseIcon">?attr/homeAsUpIndicator</item>
        <item name="collapseContentDescription">@string/toolbar_collapse_description</item>
        <item name="contentInsetStart">16dp</item>
        <item name="contentInsetStartWithNavigation">@dimen/action_bar_content_inset_with_nav</item>
        <item name="touchscreenBlocksFocus">true</item>
    </style>

    <style name="Widget.Toolbar.Button.Navigation" parent="Widget">
        <item name="background">?attr/selectableItemBackground</item>
        <item name="minWidth">56dp</item>
        <item name="scaleType">center</item>
    </style>

问题解决:

好吧,终于是找到元凶了,原来系统默认给button的最小值设置成了56dp,怪不得我咋设置高度跟padding都是这个高,唉唉!!
于是对症下药,我们修改我们button的minheight为0:(全局替换)

<EditText
                    android:minHeight="0dip"
                    android:minWidth="0dip"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content" />

51.问题描述:
透明布局点击穿透是怎么处理的?

问题解决:
在弹出层的布局中加入 Android:clickable=“true”

52.问题描述:
高德地图多个Marker标记自动缩放全部显示在屏幕中

问题解决:

LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();//存放所有点的经纬度

for(int i=0;i<markers.size();i++){
    boundsBuilder.include(markers.get(i).getPosition());//把所有点都include进去(LatLng类型)
}

aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(boundsBuilder.build(), 15));//第二个参数为四周留空宽度

53.问题描述:
自定义webview打开相机相册:

final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);

                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("image/*");

                Intent Photo = new Intent(Intent.ACTION_PICK,
                        android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

                Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
                chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[] { captureIntent, Photo });

               startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);

需要注意一个地方时,点击取消的时候,再次点击发现不能再次掉起相机,解决:

if (requestCode == FILE_CHOOSER_RESULT_CODE) {
			if (resultCode == RESULT_OK) {
				if (null == uploadMessage && null == uploadMessageAboveL) {
					return;
				}
				Uri result = data == null ? null : data.getData();
				if (result == null) {
					result = imageUri;
				}
				if (uploadMessageAboveL != null) {
					onActivityResultAboveL(requestCode, resultCode, data);
				} else if (uploadMessage != null) {
					uploadMessage.onReceiveValue(result);
					uploadMessage = null;
				}
			}else {//解决了当用户没有选择图片的时候返回再次点击无响应的bug
				if(uploadMessage != null){
					uploadMessage.onReceiveValue(null);
					uploadMessage=null;
					L.i(TAG,"--->>>onReceiveValue(null)");
				}
				if (uploadMessageAboveL != null) {
					uploadMessageAboveL.onReceiveValue(null);
					uploadMessageAboveL=null;
					L.i(TAG,"--->>>onReceiveValue(null) 2");
				}
			}

参考:http://blog.csdn.net/pkandroid/article/details/53045192

54.问题描述:
android:fitsSystemWindows=“true”,有时候会出现statusbar把界面盖住的情况.

问题解决:
一般都是fits设置的有问题,或是在布局(android:fitsSystemWindows=“false”),或是在style中fits设置为了false(false),但是statusbar没有设置为透明,造成了界面被遮盖的现象。解决办法就是上面的代码块中的代码。(要明白自己的意图再去修改)

参考:http://www.jianshu.com/p/2db7ecc50495

55、问题描述:
高德地图显示地图的时候又的地方放大后地图显示不出来。

问题原因:
在activity的onResume和onPause中少写了这两个东西(之前不写是这样可以解决切换地图黑屏问题):

@Override
    protected void onResume() {
        super.onResume();
        //必须写,要不然又的地方放大显示不出来地图
        mMapView.onResume();
    }
@Override
    protected void onPause() {
        super.onPause();
        //必须写,要不然又的地方放大显示不出来地图
        mMapView.onPause();
    }

56、问题描述:
如何监听软键盘的打开和收起状态?

问题解决:
从布局高度的变化来判断软键盘的打开和收起事件。

import android.graphics.Rect;  
import android.view.View;  
import android.view.ViewTreeObserver;  
  
import java.util.LinkedList;  
import java.util.List;  
  
public class SoftKeyboardStateHelper implements ViewTreeObserver.OnGlobalLayoutListener {  
  
    public interface SoftKeyboardStateListener {  
        void onSoftKeyboardOpened(int keyboardHeightInPx);  
        void onSoftKeyboardClosed();  
    }  
  
    private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();  
    private final View activityRootView;  
    private int        lastSoftKeyboardHeightInPx;  
    private boolean    isSoftKeyboardOpened;  
  
    public SoftKeyboardStateHelper(View activityRootView) {  
        this(activityRootView, false);  
    }  
  
    public SoftKeyboardStateHelper(View activityRootView, boolean isSoftKeyboardOpened) {  
        this.activityRootView     = activityRootView;  
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;  
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);  
    }  
  
    @Override  
    public void onGlobalLayout() {  
        final Rect r = new Rect();  
        //r will be populated with the coordinates of your view that area still visible.  
        activityRootView.getWindowVisibleDisplayFrame(r);  
  
        final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);  
        if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...  
            isSoftKeyboardOpened = true;  
            notifyOnSoftKeyboardOpened(heightDiff);  
        } else if (isSoftKeyboardOpened && heightDiff < 100) {  
            isSoftKeyboardOpened = false;  
            notifyOnSoftKeyboardClosed();  
        }  
    }  
  
    public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {  
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;  
    }  
  
    public boolean isSoftKeyboardOpened() {  
        return isSoftKeyboardOpened;  
    }  
  
    /** 
     * Default value is zero (0) 
     * @return last saved keyboard height in px 
     */  
    public int getLastSoftKeyboardHeightInPx() {  
        return lastSoftKeyboardHeightInPx;  
    }  
  
    public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {  
        listeners.add(listener);  
    }  
  
    public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {  
        listeners.remove(listener);  
    }  
  
    private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {  
        this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;  
  
        for (SoftKeyboardStateListener listener : listeners) {  
            if (listener != null) {  
                listener.onSoftKeyboardOpened(keyboardHeightInPx);  
            }  
        }  
    }  
  
    private void notifyOnSoftKeyboardClosed() {  
        for (SoftKeyboardStateListener listener : listeners) {  
            if (listener != null) {  
                listener.onSoftKeyboardClosed();  
            }  
        }  
    }  
}  

在布局中加入一下代码即可:

final SoftKeyboardStateHelper softKeyboardStateHelper = new SoftKeyboardStateHelper(findViewById(R.id.activity_main_layout);
        softKeyboardStateHelper.addSoftKeyboardStateListener(...)

原文:http://blog.csdn.net/android_heng/article/details/52316942

57、问题描述:
Edittext不能强制获取焦点了?

问题原因:
在根布局中设置了:android:descendantFocusability="blocksDescendants",然后里面又有一个view设置了点击事件,造成了对布局下面view的事件的拦截。

问题解决:删除掉:``android:descendantFocusability="blocksDescendants"即可。`

58、问题描述:
华为Meta9手机翻转用属性动画rotationY后消失问题,必须用原生的。

参考http://blog.csdn.net/thinkfuture/article/details/76571534

59、问题描述:
用Glide下载图片,然后直接设置setImageBitmap,部分手机不显示问题。

问题原因:
当图片太大太长时,setImageBitmap部分机型无效,需进行缩放。

问题解决:

/**
     * Compress image by size, this will modify image width/height.
     * Used to get thumbnail
     *
     * @param image
     * @param pixelW target pixel of width
     * @param pixelH target pixel of height
     * @return
     */
    public static Bitmap ratio(Bitmap image, float pixelW, float pixelH) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, os);
        if (os.toByteArray().length / 1024 > 1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
            os.reset();//重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, 50, os);//这里压缩50%,把压缩后的数据存放到baos中
        }
        ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        //开始读入图片,此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        newOpts.inPreferredConfig = Bitmap.Config.RGB_565;
        Bitmap bitmap = BitmapFactory.decodeStream(is, null, newOpts);
        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        float hh = pixelH;// 设置高度为240f时,可以明显看到图片缩小了
        float ww = pixelW;// 设置宽度为120f,可以明显看到图片缩小了
        //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        int be = 1;//be=1表示不缩放
        if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0) be = 1;
        newOpts.inSampleSize = be;//设置缩放比例
        //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        is = new ByteArrayInputStream(os.toByteArray());
        bitmap = BitmapFactory.decodeStream(is, null, newOpts);
        //压缩好比例大小后再进行质量压缩
//     return compress(bitmap, maxSize); // 这里再进行质量压缩的意义不大,反而耗资源,删除
        return bitmap;
    }

    private void loadBigImage(final String path, final PhotoModel photoModel) {
        //再加载原图
        Glide.with(getContext().getApplicationContext()).load(path)
                .asBitmap()
                .into(new SimpleTarget<Bitmap>(IMAGE_MAX_SIZE, IMAGE_MAX_SIZE) {
                    @Override
                    public void onResourceReady(final Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                        //图片宽度或者高度超过屏幕的宽度或高度的2倍就开始压缩到屏幕大小
                        int maxMultiple = 1;
                        int w = resource.getWidth();
                        int h = resource.getHeight();
                        int scaleH = h / w;
                        int scaleW = w / h;
                        Log.i(TAG, "--->>>onResourceReady w:" + w + ",h:" + h + ",scaleH:" + scaleH + ",scaleW:" + scaleW + ",sH:" + sH + ",sW:" + sW);
                        //缩放
                        if ((w > sW && w / sW > maxMultiple) || (h > sH && h / sH > maxMultiple)) {
                            Log.i(TAG,"--->>>loadBigImage ratio");
                            Bitmap newBmp = ratio(resource,sW,sH);
                            ivContent.setImageBitmap(newBmp);
                        }else{
                            Log.i(TAG,"--->>>loadBigImage no ratio");
                            ivContent.setImageBitmap(resource);
                        }
                    }

                    @Override
                    public void onLoadFailed(Exception e, Drawable errorDrawable) {
                        super.onLoadFailed(e, errorDrawable);
                    }

                    @Override
                    public void onLoadStarted(Drawable placeholder) {
                        super.onLoadStarted(placeholder);
                        Log.i(TAG, "--->>>onLoadStarted");
                    }
                });
    }

参考:http://blog.csdn.net/misa92/article/details/72828087

60、问题描述:
游客登录,退出登录,同一账号挤下来跳转登录界面的方案

问题解决:
首先在Applicaiton中通过注册registerActivityLifecycleCallbacks记录每个activity中记录每个activity到自己维护的集合中。
①登录挤下来:
在application中加入每个acticity,然后挤下来的时候关闭掉所有activity再跳转到登录界面
②登录后-》点击设置-》点击退出后关闭除了MainActivity以外的所有activity再跳转到登录界面
③游客进入后的登录:
已有手机号登录成功后,关闭掉前登录相关activity即可
未注册用户关闭掉注册相关activity即可

61、问题描述:
今天遇到H5微信支付的时候,IOS没有问题,android的webview调用的时候报错:商家参数格式有误

问题解决:

public class WebViewTestActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_view_test);
        WebView webView = ((WebView) findViewById(R.id.webviewtest));

        WebSettings settings = webView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setDefaultTextEncodingName("UTF-8");
        webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        webView.setWebChromeClient(new WebChromeClient());
        WebViewClient webViewClient = new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                // 如下方案可在非微信内部WebView的H5页面中调出微信支付
                if (url.startsWith("weixin://wap/pay?")) {
                    Intent intent = new Intent();
                    intent.setAction(Intent.ACTION_VIEW);
                    intent.setData(Uri.parse(url));
                    startActivity(intent);
                    return true;
                } else {
                    Map<String, String> extraHeaders = new HashMap<String, String>();
                    extraHeaders.put("Referer", "http://wxpay.wxutil.com");
                    view.loadUrl(url, extraHeaders);
                }
                return true;
            }

            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, android.net.http.SslError error) { // 重写此方法可以让webview处理https请求
                handler.proceed();
            }
        };
        webView.setWebViewClient(webViewClient);
        webView.loadUrl("http://wxpay.wxutil.com/mch/pay/h5.v2.php");
    }

}

出现的错误无外乎就是微信官网列出的那几种,可以看这个链接 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4 。比如我在原生系统上最开始报的错误就是:商家参数格式有误,请联系商家解决,这个实际上官方给出了解决方案:

2. 如果是APP里调起H5支付,需要在webview中手动设置referer,如

(Map extraHeaders = new HashMap();
extraHeaders.put("Referer", "商户申请H5时提交的授权域名");//例如 http://www.baidu.com ))

附上微信的官方文档地址,一些错误可以在这里面找到原因 点击打开链接

参考:http://blog.csdn.net/a1030260075/article/details/79036620
https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4

62、问题描述:
华为Mate9的8.0系统调用系统相机后,返回先返回到桌面上再进入上一页的:

问题解决:
这个activity的style设置windowIsTranslucent为true,那么返回后的看到的现象好像是先回到桌面上再进入此界面,体验不好,所以将windowIsTranslucent去掉了或者设置成false

63、关于自定义视频录制问题总结:
一、变形问题:
自定义视频四个重要的地方:
①根据需求找出一个Camera预览的合适尺寸Pre_Size并设置。
②根据Pre_Size去设置代码中的SurfaceView的尺寸。
③判断如果摄像头的VideoSizes集合中包含Pre_Size的宽高,则取这个宽高,反之在VideoSizes中找一组合适的Video_Size并设置。
④根据VideoSize再次去设置代码中的SurfaceView的尺寸。

示例代码:

Size size =  CameraUtil.getInstance().getCommonPropSizeByHeight(mSupportedPreviewSizes,SMALL_VIDEO_WIDTH);
int previewHeight = size.height;
int previewWidth = size.width;
mParameters.setPreviewSize(previewWidth, previewHeight);
if(mOnSizeListener != null){
    mOnSizeListener.onSize(previewHeight,previewWidth);
}

private void initSurfaceView(int v_width,int v_height) {
        final int w = DeviceUtils.getScreenWidth(this);
        int width = w;
        int height = w * v_height / v_width;
        RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mSurfaceView.getLayoutParams();
        lp.width = width;
        lp.height = height;
        mSurfaceView.setLayoutParams(lp);
    }

xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#000000">
    <RelativeLayout
        android:id="@+id/camera_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <SurfaceView
            android:id="@+id/record_preview"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </RelativeLayout>
</RelativeLayout>

List<Camera.Size> videoSizes = mParameters.getSupportedVideoSizes();
boolean isContain = CameraUtil.getInstance().isVideoSizesContainPropSize(width, height, videoSizes);
if (!isContain) {
    Camera.Size supportedVideoSizes = CameraUtil.getInstance().getCommonPropSizeByHeight(videoSizes, SMALL_VIDEO_WIDTH);
    width = supportedVideoSizes.width;
    height = supportedVideoSizes.height;
}
mMediaRecorder.setVideoSize(width, height);
//fhl add 20170511 值越高越清晰
mMediaRecorder.setVideoEncodingBitRate(7 * 1024 * 1024);
if (onVideoSizeChange != null) {
    onVideoSizeChange.onSize(height, width);
}
/**
* 图片大小集合中是否包含预览图片大小
* @param preWidth
* @param PreHeight
* @param videoSizes
* @return
*/
public boolean isVideoSizesContainPropSize(int preWidth, int PreHeight, List<Camera.Size> videoSizes) {
   if(videoSizes != null){
       for(Camera.Size size : videoSizes){
           if(size.width == preWidth && size.height == PreHeight){
               return true;
           }
       }
   }
   return false;
}
/**
 * 相机里面的宽度和高度是反的
 *
 * @param list
 * @param minHeight
 * @return
 */
public Camera.Size getCommonPropSizeByHeight(List<Camera.Size> list, int minHeight) {
    Collections.sort(list, ascendSizeComparator_Height);
    int i = 0;
    for (Camera.Size s : list) {
        int height = s.height;
        float minWidth = height * 1.5f;//防止正方形
        if ((height >= minHeight) && s.width >= minWidth) {
            break;
        }
        i++;
    }
    if (i == list.size()) {
        i = list.size() - 1;//如果没找到,就选最大的size
    }
   
    return list.get(i);
}


同②代码设置。

64、自定义checkbox背景问题:

<CheckBox android:id="@+id/checkbox1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/wx_checkbox_style"
    android:button="@null"
    android:checked="true"
    xmlns:android="http://schemas.android.com/apk/res/android" />

wx_checkbox_style.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/ic_cb_selected" android:state_checked="true"/>
    <item android:drawable="@drawable/ic_cb_default" android:state_checked="false"/>
    <item android:drawable="@drawable/ic_cb_default"/>

</selector>

65、checkbox设置为不可点击:
点击的适合焦点传递给父布局:

android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"

②在布局的根加上:

android:descendantFocusability="blocksDescendants"

66、TextView设置android:gravity="center"失效:
1.在程序中调用TextView的方法:

setIncludeFontPadding (boolean includepad)

2.或者在xml中加入下句:

android:includeFontPadding=“false”

67、自定义顶部圆角图片:

public class MyRoundedImageView extends ImageView {
    //圆角的半径,依次为左上角xy半径,右上角xy半径,右下角xy半径,左下角xy半径
    private float[] rids = {10.0f, 10.0f, 10.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f,};
    public MyRoundedImageView(Context context) {
        super(context);
    }
    public MyRoundedImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public MyRoundedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    protected void onDraw(Canvas canvas) {
        Path path = new Path();
        int w = this.getWidth();
        int h = this.getHeight();
        /*向路径中添加圆角矩形。radii数组定义圆角矩形的四个圆角的x,y半径。radii长度必须为8*/
        path.addRoundRect(new RectF(0, 0, w, h), rids, Path.Direction.CW);
        canvas.clipPath(path);
        super.onDraw(canvas);
    }
}

用法:

<RelativeLayout
        android:layout_width="200dp"
        android:layout_height="112dp">

        <!-- ic_wh 为白色背景图片 -->
        <!--<leifu.alipayhome.view.MyRoundedImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/ic_wh"/>

        <leifu.alipayhome.view.MyRoundedImageView
            android:id="@+id/id_test"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitCenter" />-->
        
        <leifu.alipayhome.view.MyRoundedImageView
            android:id="@+id/id_test"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop" />
    </RelativeLayout>

67、外部包冲突问题:
报错:Error:(631) Attribute “android:translationZ” has already been defined

问题解决:
com.android.support.constraint:constraint-layout:1.0.2
原因是一个工程里面有很多个这种包,版本不一致导致的冲突,改成一致即可。

68、surfaceView播放视频不压缩:
https://github.com/linsea/UniversalVideoView

使用方法
完整的使用方法请参考项目里的Sample.


1. 在build.gradle文件上加入以下依赖包.

dependencies {
      compile 'com.linsea:universalvideoview:1.1.0@aar'
 }

2. 在布局文件中加入自定义View,注意要使UniversalVideoView和UniversalMediaController位于同一个父Layout中, 这样控制条才会浮在视频之上.


            <FrameLayout
                android:id="@+id/video_layout"
                android:layout_width="fill_parent"
                android:layout_height="200dp"
                android:background="@android:color/black">

                <com.universalvideoview.UniversalVideoView
                    android:id="@+id/videoView"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:layout_gravity="center"
                    app:uvv_autoRotation="true"
                    app:uvv_fitXY="false" />

                <com.universalvideoview.UniversalMediaController
                    android:id="@+id/media_controller"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    app:uvv_scalable="true" />

            </FrameLayout>

3. 在onCreate方法中设置相关事件的监听.


View mBottomLayout;
View mVideoLayout;
UniversalVideoView mVideoView;
UniversalMediaController mMediaController;

mVideoView = (UniversalVideoView) findViewById(R.id.videoView);
mMediaController = (UniversalMediaController) findViewById(R.id.media_controller);
mVideoView.setMediaController(mMediaController);

mVideoView.setVideoViewCallback(new UniversalVideoView.VideoViewCallback() {
    @Override
    public void onScaleChange(boolean isFullscreen) {
        this.isFullscreen = isFullscreen;
        if (isFullscreen) {
            ViewGroup.LayoutParams layoutParams = mVideoLayout.getLayoutParams();
            layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
            layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
            mVideoLayout.setLayoutParams(layoutParams);
            //设置全屏时,无关的View消失,以便为视频控件和控制器控件留出最大化的位置
            mBottomLayout.setVisibility(View.GONE);
        } else {
            ViewGroup.LayoutParams layoutParams = mVideoLayout.getLayoutParams();
            layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
            layoutParams.height = this.cachedHeight;
            mVideoLayout.setLayoutParams(layoutParams);
            mBottomLayout.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void onPause(MediaPlayer mediaPlayer) { // 视频暂停
        Log.d(TAG, "onPause UniversalVideoView callback");
    }

    @Override
    public void onStart(MediaPlayer mediaPlayer) { // 视频开始播放或恢复播放
        Log.d(TAG, "onStart UniversalVideoView callback");
    }

    @Override
    public void onBufferingStart(MediaPlayer mediaPlayer) {// 视频开始缓冲
        Log.d(TAG, "onBufferingStart UniversalVideoView callback");
    }

    @Override
    public void onBufferingEnd(MediaPlayer mediaPlayer) {// 视频结束缓冲
        Log.d(TAG, "onBufferingEnd UniversalVideoView callback");
    }

});

注意:
UniversalVideoView 没有保存播放的状态,如播放到第几分钟了,所以需要应用自己保存这些状态并恢复.
如果为了避免在旋转屏幕时系统重启Activity,需要添加Activity的属性:
android:configChanges="orientation|keyboardHidden|screenSize

4 定制属性
为了保证定制UI的灵活度,提供以下属性:

uvv_fitXY

UniversalVideoView的属性,布尔值,true时设置视频缩放时在X,Y方向上铺满View设置的宽度和高度,这样可能使视频变形.false时则缩放时保持视频的长宽比例,与SDK中的VideoView类似.


uvv_autoRotation

UniversalVideoView的属性,布尔值,true时视频会根据重力响应通知客户进行全屏与非全屏之间的切换.

uvv_scalable

UniversalMediaController属性,布尔值,是否显示控制条右下方的缩放按钮,如果不想全屏播放时,可以设置为false不显示.


  • 3
    点赞
  • 0
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值