Androidソース生コードバグによる連続通知アプリの死
2709 ワード
プロジェクトでは、同じ通知を連続的に送信すると、アプリケーションが遅くなり、最終的にカードが死んでしまうことがわかりました.
デバッグでは、毎回newの新しいRemoteViewが詰まって死なないことがわかりました.これはなぜですか.
追跡はandroidソースコードに入ってやっと原因を発見した.
通知の送信を適用することは、プロセスが対話するプロセスです.appは通知クラス(Notification)を通知サービスプロセスに転送する必要がある.通知サービスプロセス管理による通知の送信.
Notificationの構築では、RemoteViewを含むParcelableインタフェースが実装されています.カード死の原因はRemoteViewの実現原理にある.
RemoteViewは、setImageView Resource()などのViewコントロールの操作を容易にする一連の方法を提供しています.その実現メカニズムは、次のとおりです.
RemoteViewの内部でアクションクラスを設定します.
RemoteViewは、Action抽象クラスの配列を維持します.
RemoteView内のViewコントロールの各操作は、ReflectionAction(Actionに継承)に対応します.
ReflectionActionの役割は、反射呼び出しViewの関連メソッドを使用して、View図面を操作することです.
図面を描くときにRemoteViewのAction配列を巡回し、反射によって関連するViewを呼び出す方法を取得します.
このRemoteViewが維持するAction配列は増加するだけで減少しないということが、アプリケーションの死の原因となっています.
つまり、毎回同じRemoteViewを使用して通知を送信すると、通知を送信するたびに、以前のすべての操作が繰り返されます.前回よりも多くの時間を消費し、通知欄のレイアウトが複雑であれば、notify(int id,Notification notification)メソッドは長い時間を消費し、アプリケーションのカードが死んでしまいます.
個人的には、これはAndroidのバグだと思いますが、確かにこの問題を根源的に解決する有効な方法はなく、通知を出すたびにnewが新しいRemoteViewが出てくるだけで、Actionに余分な操作はありません.時間がかかる.cloneの元のRemoteViewではなく、clone()がAction配列をコピーし、最終的には遅いことに注意してください.
デバッグでは、毎回newの新しいRemoteViewが詰まって死なないことがわかりました.これはなぜですか.
追跡はandroidソースコードに入ってやっと原因を発見した.
通知の送信を適用することは、プロセスが対話するプロセスです.appは通知クラス(Notification)を通知サービスプロセスに転送する必要がある.通知サービスプロセス管理による通知の送信.
Notificationの構築では、RemoteViewを含むParcelableインタフェースが実装されています.カード死の原因はRemoteViewの実現原理にある.
RemoteViewは、setImageView Resource()などのViewコントロールの操作を容易にする一連の方法を提供しています.その実現メカニズムは、次のとおりです.
RemoteViewの内部でアクションクラスを設定します.
/**
* Base class for all actions that can be performed on an
* inflated view.
*
* SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
*/
private abstract static class Action implements Parcelable {
RemoteViewは、Action抽象クラスの配列を維持します.
/**
* An array of actions to perform on the view tree once it has been
* inflated
*/
private ArrayList mActions;
RemoteView内のViewコントロールの各操作は、ReflectionAction(Actionに継承)に対応します.
/**
* Base class for the reflection actions.
*/
private class ReflectionAction extends Action {
ReflectionActionの役割は、反射呼び出しViewの関連メソッドを使用して、View図面を操作することです.
図面を描くときにRemoteViewのAction配列を巡回し、反射によって関連するViewを呼び出す方法を取得します.
@Override
public void apply(View root, ViewGroup rootParent) {
...
Class klass = view.getClass();
Method method;
try {
method = klass.getMethod(this.methodName, getParameterType());
...
method.invoke(view, this.value);
}
...
}
このRemoteViewが維持するAction配列は増加するだけで減少しないということが、アプリケーションの死の原因となっています.
private void addAction(Action a) {
if (mActions == null) {
mActions = new ArrayList();
}
mActions.add(a);
// update the memory usage stats
a.updateMemoryUsageEstimate(mMemoryUsageCounter);
}
つまり、毎回同じRemoteViewを使用して通知を送信すると、通知を送信するたびに、以前のすべての操作が繰り返されます.前回よりも多くの時間を消費し、通知欄のレイアウトが複雑であれば、notify(int id,Notification notification)メソッドは長い時間を消費し、アプリケーションのカードが死んでしまいます.
private void performApply(View v, ViewGroup parent) {
if (mActions != null) {
final int count = mActions.size();
for (int i = 0; i < count; i++) {
Action a = mActions.get(i);
a.apply(v, parent);
}
}
}
個人的には、これはAndroidのバグだと思いますが、確かにこの問題を根源的に解決する有効な方法はなく、通知を出すたびにnewが新しいRemoteViewが出てくるだけで、Actionに余分な操作はありません.時間がかかる.cloneの元のRemoteViewではなく、clone()がAction配列をコピーし、最終的には遅いことに注意してください.