2014-12-16 10:06
1.
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
at android.app.ContextImpl.startActivity(ContextImpl.java:1161)
at android.app.ContextImpl.startActivity(ContextImpl.java:1148)
原因是:
Context中有一个startActivity方法,Activity继承自Context,重载了startActivity方法。如果使用 Activity的startActivity方法,不会有任何限制,而如果使用Context的startActivity方法的话,就需要开启一个新的task,遇到上面那个异常的,都是因为使用了Context的startActivity方法。解决办法是,加一个flag。intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2.
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:
如果调出的Activtivity只是一个功能片段,并没有实际的意义,也没有必要出现在长按Home键调出最近使用过的程序类表中,那么使用FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Intent intent = new Intent(this, TestActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);
==========================================================================================
==========================================================================================
2015年01月12号
3.Android4.4.X版本,开启或关闭飞行模式时,报出异常:
E/AndroidRuntime( 2775): FATAL EXCEPTION: main
E/AndroidRuntime( 2775): Process: com.android.deskclock, PID: 2775
E/AndroidRuntime( 2775): java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.AIRPLANE_MODE from pid=2775, uid=10057
E/AndroidRuntime( 2775): at android.os.Parcel.readException(Parcel.java:1472)
E/AndroidRuntime( 2775): at android.os.Parcel.readException(Parcel.java:1426)
E/AndroidRuntime( 2775): at android.app.ActivityManagerProxy.broadcastIntent(ActivityManagerNative.java:2491)
E/AndroidRuntime( 2775): at android.app.ContextImpl.sendBroadcast(ContextImpl.java:1243)
E/AndroidRuntime( 2775): at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:365)
E/AndroidRuntime( 2775): at com.android.deskclock.alarmclock.Alarms.closeAirplaneMode(Alarms.java:1863)
E/AndroidRuntime( 2775): at com.android.deskclock.alarmclock.LockAlarmFullActivity$ControlAlarm.dismiss(LockAlarmFullActivity.java:955)
E/AndroidRuntime( 2775): at com.android.deskclock.alarmclock.LockAlarmFullActivity$4.onTouch(LockAlarmFullActivity.java:617)
E/AndroidRuntime( 2775): at android.view.View.dispatchTouchEvent(View.java:7780)
E/AndroidRuntime( 2775): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2316)
虽然已经在AndroidManifest.xml声明了权限,但是依旧会报出异常。后查需要在AndroidManifest.xml 添加 android:sharedUserId="android.uid.system"
如果上面方法仍不奏效,那么可以使该apk的签名和平台保持一致。即使用源码平台默认签名对该apk进行重新签名,并push到 systen/app下面。那么操作Setttings表时就具有了系统权限。
==========================================================================================
==========================================================================================
2015年01月15日:
4.
Android平台继承SQLiteOpenHelper实现的CRUD操作,默认情况不允许数据库降级,否则显示会抛出异常:
throw new SQLiteException("Can't downgrade database from version " +oldVersion + " to " + newVersion);
01-14 20:29:22.290: E/AndroidRuntime(2722): FATAL EXCEPTION: AsyncHandler
01-14 20:29:22.290: E/AndroidRuntime(2722): Process: com.android.deskclock, PID: 2722
01-14 20:29:22.290: E/AndroidRuntime(2722): android.database.sqlite.SQLiteException: Can't downgrade database from version 10 to 7
01-14 20:29:22.290: E/AndroidRuntime(2722): at android.database.sqlite.SQLiteOpenHelper.onDowngrade(SQLiteOpenHelper.java:361)
01-14 20:29:22.290: E/AndroidRuntime(2722): at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:255)
/**
* Called when the database needs to be downgraded. This is strictly similar to
* {@link #onUpgrade} method, but is called whenever current version is newer than requested one.
* However, this method is not abstract, so it is not mandatory for a customer to
* implement it. If not overridden, default implementation will reject downgrade and
* throws SQLiteException
*
* <p>
* This method executes within a transaction. If an exception is thrown, all changes
* will automatically be rolled back.
* </p>
*
* @param db The database.
* @param oldVersion The old database version.
* @param newVersion The new database version.
*/
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
throw new SQLiteException("Can't downgrade database from version " +
oldVersion + " to " + newVersion);
}
当然可以复写父类方法允许数据库降级,前提是对数据库版本号毫不关心。因此通常不会去复写该方法,因为:
You should care about this "Database Version thing" if ever your database schema is ever going to change
==========================================================================================
==========================================================================================
2015年01月26日:
5. WindowManager$BadTokenException: Unable to add window…is not valid; is your activity running?
01-26 11:20:07.365 11836 11836 E AndroidRuntime: Process: com.mediatek.schpwronoff, PID: 11836
01-26 11:20:07.365 11836 11836 E AndroidRuntime: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@41f06b68 is not valid; is your activity running?
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at android.view.ViewRootImpl.setView(ViewRootImpl.java:637)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:261)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at android.app.Dialog.show(Dialog.java:329)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at android.app.Activity.showDialog(Activity.java:3182)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at android.app.Activity.showDialog(Activity.java:3132)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at com.mediatek.schpwronoff.ShutdownActivity$1.onTick(ShutdownActivity.java:93)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at android.os.CountDownTimer$1.handleMessage(CountDownTimer.java:124)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:110)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at android.os.Looper.loop(Looper.java:193)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5332)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:515)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:831)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:647)
01-26 11:20:07.365 11836 11836 E AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)
======================================================
FATAL EXCEPTION: main
android.view.WindowManager$BadTokenException: Unable to add window -- token android.app.LocalActivityManager$LocalActivityRecord@4051c0e0 is not valid; is your activity running?
at android.view.ViewRoot.setView(ViewRoot.java:558)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.view.Window$LocalWindowManager.addView(Window.java:433)
at android.app.Dialog.show(Dialog.java:265)
at net.reecam.CameraSearch$3.onClick(CameraSearch.java:103)
at android.view.View.performClick(View.java:2532)
at android.view.View$PerformClick.run(View.java:9308)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:150)
at android.app.ActivityThread.main(ActivityThread.java:4293)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
问题原因:
看报错关键词提示: Unable to add window 、LocalActivityManager、is your activity running,再结合应用程序中用到了AcitivityGroup来管理子Activity这个环境,而报错的前提就是在子Activity上弹出ProgressDialog进度条会话框,提示如上报错提示。就是说不能在子Activity上添加此窗口,LocalActivityManager$LocalActivityRecord@4051c0e0 is not valid就是说当前Activity管理器中此4051c0e0代表的Acitivity是无效的,也就是网上资料所说找不到它依附的Acitivity。
解决办法:
将new DialogToast(this);
改为:
new DialogToast(getParent());
就OK了。
是由于有activity时依附于另一个activity的,当被依附的activity产生错误的时候,该activity没有了靠山而产生错误(或者是调用了一个已经被finish()的activity)。一般在创建alertdialog.builder是很容易见到。
对于这个错误还没有根本的解决办法,唯一的办法就是改变该activity依附于另一activity的事实,将其放入另一activity。
Android利用ActivityGroup加载子Activity,子Activity调用对话框,弹出:
ERROR/AndroidRuntime(10104): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token android.app.LocalActivityManager$LocalActivityRecord@45a58ee0 is not valid; is your activity running?
原因分析:
因为new对话框的时候,参数content 指定成了this,即指向当前子Activity的content。但子Activity是动态创建的,不能保证一直存在。其父Activity的content是稳定存在的,所以有下面的解决办法。
解决办法:
将content替换为getParent()即可。
==========================================================================================
==========================================================================================
2015年01月27
6.android.os.BadParcelableException: ClassNotFoundException when unmarshalling:解决办法
例如在用AlarmManager的时候
1 AlarmManager alarmMgr = (AlarmManager) mContext
2 .getSystemService(Context.ALARM_SERVICE);
3 Intent intent = new Intent(ALARM_ALERT);
4 // intent.setExtrasClassLoader(DBTask.class.getClassLoader());
5 Bundle mBundle=new Bundle();
6 mBundle.putParcelable(AlarmMeReceiver.DB_TASK_KEY,task);
7 intent.putExtras(mBundle);
8 int id=Integer.valueOf(task.id);
9 PendingIntent pendIntent = PendingIntent.getBroadcast(
10 mContext.getApplicationContext(), id, intent,
11 PendingIntent.FLAG_UPDATE_CURRENT);
12 long triggerAtTime = task.time;
13 alarmMgr.set(AlarmManager.RTC_WAKEUP , triggerAtTime, pendIntent);
通过第6行 intent传提一个Parcelable对象 (Parcelable里面没有问题)
报android.os.BadParcelableException: ClassNotFoundException when unmarshalling错误可以加上
intent.setExtrasClassLoader(DBTask.class.getClassLoader());
原因是android.platform.frameworks.base/core/java/android/content/Intent.java
5052 try {
5053 Bundle newb = new Bundle(other.mExtras);
5054 newb.putAll(mExtras);
5055 mExtras = newb;
5056 } catch (RuntimeException e) {
5057 // Modifying the extras can cause us to unparcel the contents
5058 // of the bundle, and if we do this in the system process that
5059 // may fail. We really should handle this (i.e., the Bundle
5060 // impl shouldn't be on top of a plain map), but for now just
5061 // ignore it and keep the original contents. :(
5062 Log.w("Intent", "Failure filling in extras", e);
5063 }
android 中自定义的对象序列化的问题有两个选择一个是Parcelable,另外一个是Serializable。
一 序列化原因:
1.永久性保存对象,保存对象的字节序列到本地文件中;
2.通过序列化对象在网络中传递对象;
3.通过序列化在进程间传递对象。
二 至于选取哪种可参考下面的原则:
1.在使用内存的时候,Parcelable 类比Serializable性能高,所以推荐使用Parcelable类。
2.Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
3.Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点, 也不提倡用,但在这种情况下,还是建议你用Serializable 。
==============================================================================================================
android.os.BadParcelableException: ClassNotFoundException when unmarshalling
本文主要分析android.os.BadParcelableException: ClassNotFoundException when unmarshalling这个异常的原因及解决方法,解释了android的class loader.
一、现象:
应用打开,home键到后台,过一段时间打开,偶现fc,log如下:
|
E/AndroidRuntime(9085): Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: *.*.*.*.Layout$Config
E/AndroidRuntime(9085): at android.os.Parcel.readParcelable(Parcel.java:2077)
E/AndroidRuntime(9085): at *.*.*.<init>(Layout.java:105)
|
程序中的写法是
|
publicConfigconfig;
publicRowView(Parcelin){
type=in.readString();
interfaceUrl=in.readString();
size=in.readInt();
config=in.readParcelable(null);
}
|
报错的语句即为config = in.readParcelable(null);
二、原因分析:
根据android文档介绍:
readParcelable (ClassLoader loader)
loader A ClassLoader from which to instantiate the Parcelable object, or null for the default class loader.
即loader为空时系统会采取默认的class loader。
Android有两种不同的classloaders:framework classloader和apk classloader,其中framework classloader知道怎么加载android classes,apk classloader知道怎么加载you code,apk classloader继承自framework classloader,所以也知道怎么加载android classes。
在应用刚启动时,默认class loader是apk classloader,但在系统内存不足应用被系统回收会再次启动,这个默认class loader会变为framework classloader了,所以对于自己的类会报ClassNotFoundException。
三、解决方法:
将config = in.readParcelable(null);改为config = in.readParcelable(Config.class.getClassLoader());
Config.class.getClassLoader()即为apk classloader, 其中Config.class可以改为你程序中自己写的任意类,因为他们同样指向apk loader
嘿嘿,试着改为config = in.readParcelable(Activity.class.getClassLoader());你会发现依然ClassNotFoundException因为Activity.class.getClassLoader()指向的是framework classloader
四、如何测试重现这个问题,方便测试呢:
重现这个问题即使的应用被系统回收,把设置->开发者选项->不保留活动开关打开,打开测试程序按home键,再打开测试程序就会执行到这句。
如果你是在onSaveInstanceState中保存
savedInstanceState.putParcelable(key, value),则需要设置Bundle的class loader,如下:
savedInstanceState.setClassLoader(getClass().getClassLoader());
PS:
(1)、readParcelableArray(ClassLoader loader), readParcelable, readArray,readArrayList, readBundle, readHashMap, readParcelable, readSparseArray, readValue, readList, readMap也有可能报上面的异常
相关博客:
关于Parcelable以及Parcelable和Serializable的区别的区别,可参考以前写的:http://www.cnblogs.com/trinea/archive/2012/11/09/2763213.html
参考:http://stackoverflow.com/questions/13997550/unmarshalling-errors-in-android-app-with-custom-parcelable-classes
http://developer.android.com/reference/android/os/Parcel.html#readParcelable(java.lang.ClassLoader
=========================================================================================
关于这个“Activity之间对象传递的两种方法(Serializable,Parcelable)”我是通过别人的博客里学习到的,引用自:http://blog.csdn.net/Android_Tutor/archive/2010/07/16/5740845.aspx。
本来是要直接附上Demo的,可惜这里面没找到加入本地文件的地方。大家需要的还是到作者那去看看吧。
首先,我这里主要说下Parcelable 的用法。
1、定义对象类,类实现Parcelable接口。且要实现Parcelable接口的几个必要方法。如我的Question类中的相关方法的实现:
private Question(Parcel in){
question_title = ParcelUtils.readStringFromParcel(in);
created_time = ParcelUtils.readStringFromParcel(in);
question_id = in.readInt();
creator_name = ParcelUtils.readStringFromParcel(in);
answer_list = new Group<Answer>();
int answerSize = in.readInt();
for (int i = 0; i < answerSize; i++) {
Answer answer = in.readParcelable(Answer.class.getClassLoader());
answer_list.add(answer);
}
}
public static final Question.Creator<Question> CREATOR = new Parcelable.Creator<Question>() {
public Question createFromParcel(Parcel in) {
return new Question(in);
}
@Override
public Question[] newArray(int size) {
return new Question[size];
}
};
@Override
public void writeToParcel(Parcel out, int flags) {
ParcelUtils.writeStringToParcel(out, question_title);
ParcelUtils.writeStringToParcel(out, created_time);
out.writeInt(question_id);
ParcelUtils.writeStringToParcel(out, creator_name);
if (answer_list != null) {
out.writeInt(answer_list.size());
for (int i = 0; i < answer_list.size(); i++) {
out.writeParcelable(answer_list.get(i), flags);
}
} else {
out.writeInt(0);
}
}
注意:
方法private Question(Parcel in){}和方法public void writeToParcel(Parcel out, int flags) {}中变量顺序是一致的,是一一对应的。其中,
Question(Parcel in)是变量的存储;
writeToParcel(Parcel out, int flags) 是变量的读取。
2、程序中的应用:
1)存储
Intent intent = new Intent(Question1.this,Question2.class);
Bundle bundle = new Bundle();
bundle.putParcelable("question_objs", question);
intent.putExtras(bundle);
startActivity(intent);
2)提取
Intent intent = getIntent();
Question que = intent.getParcelableExtra("question_objs");
3)接下来就可以使用question对象了。
其次,在使用Parcelable的过程中,曾报异常:
Caused By:android.os.BadParcelableException: ClassNotFoundException when unmarshalling:
at android.os.Parcel.readParcelable(Parcel.java )
该异常是由于,我在对象类得定义中,成员变量的读取和存储没有一一对应,导致成员变量赋值错误,从而导致上述异常,所以,在上述对象类的定义说明中加了“注意:”