私は、JNIとマルチスレッドのスキルを磨くために書いた非常にシンプルなアプリを持っています。これは、ASCII文字の文字列をバイナリ文字列に変換するか、バイナリ文字列をASCII文字列に変換します。各変換の背後にある計算はネイティブlibを介して処理され、ネイティブコードへの各呼び出しは、UIを中断しないように、AsyncTaskを使用して独自のスレッドで実行されます。問題は、UIウィジェットがサイズや位置を変更する必要があるときにonLayoutが呼び出されるたびに、新しい画像が、まだ表示されている古い画像の上に置き換えられるのではなく、上に配置されることです。可能性のある原因(JNIモジュール、AsyncTaskモジュール)を削除しようとしましたが、その機能が削除され、UIのみが残っている場合でも、古いビューを置き換えるのではなく、新しいUIビューがオーバーラップする同じ結果が表示されます。以下の私のコードからわかるように、また、現在アクティブにしているより柔軟なカスタムaddViewモデルに加えて、UI階層モデリングへの古いsetContentView(...)アプローチをさまざまに試しましたが、結果は同じでした。注:これはデバイスでのみ発生します(最新の4.2.1を実行しているNexus7および4.0.2を実行しているNexusS)。エミュレータでは、すべてが正常に機能します。これはGLESの呼び出しに関係しているように見えますが、私はこのアプリで自分自身を作成していません。明らかに、これはデバイス上のすべてのアプリで発生しているわけではないため、OSの問題ではないようです... エミュレータでは、すべてが正常に機能します。これはGLESの呼び出しに関係しているように見えますが、私はこのアプリで自分自身を作成していません。明らかに、これはデバイス上のすべてのアプリで発生しているわけではないため、OSの問題ではないようです... エミュレータでは、すべてが正常に機能します。これはGLESの呼び出しに関係しているように見えますが、私はこのアプリで自分自身を作成していません。明らかに、これはデバイス上のすべてのアプリで発生しているわけではないため、OSの問題ではないようです...
アクティビティクラス:
package cresco.ai.asciitobinstring.core;
import android.app.Activity;
import android.os.Bundle;
public class AsciiToBinActivity_Minimalist extends Activity{
private AsciiToBin_Main hMain;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
hMain = new AsciiToBin_Main(this);
hMain.init();
}
@Override
protected void onResume(){
super.onResume();
}
@Override
protected void onPause(){
super.onPause();
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
}
@Override
protected void onRestart(){
super.onRestart();
}
@Override
protected void onDestroy(){
super.onDestroy();
}
}
メインマネージャークラス:
package cresco.ai.asciitobinstring.core;
import cresco.ai.asciitobinstring.gui.ConversionViewController;
import cresco.ai.asciitobinstring.gui.DefineLayoutParams;
import cresco.ai.asciitobinstring.gui.TutorialViewController;
import cresco.ai.asciitobinstring.math.StringConverter;
import android.app.Activity;
import android.content.res.AssetManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.ViewFlipper;
public class AsciiToBin_Main {
private Activity hAct;
private View mvMainView;
private ViewFlipper mvRootViewFlipper;
private ConversionViewController mvConversionViewController;
private TutorialViewController mvTutorialViewController;
private RelativeLayout mvRootRL;
private AssetManager mvAssetManager;
private LayoutInflater mvInflater;
private StringConverter mvConverter;
public AsciiToBin_Main(Activity act){
hAct = act;
mvConverter = new StringConverter(this);
mvRootRL = new RelativeLayout(hAct);
hAct.addContentView(mvRootRL,
DefineLayoutParams.getParams(DefineLayoutParams.getMM()));
//hAct.setContentView(mvRootRL);
///hAct.setContentView(R.layout.conversion_layout);
}
public void init(){
//Add the viewgroup subclass viewflipper to the rootRL
mvRootViewFlipper = new ViewFlipper(hAct);
mvRootRL.addView(mvRootViewFlipper);
//Instantiate our conversion view controller
mvConversionViewController = new ConversionViewController(this);
mvTutorialViewController = new TutorialViewController(this);
//Fire up the conversion view
mvConversionViewController.initGUI();
mvConversionViewController.initSpinnerElements();
//Fire up the tutorial view
mvTutorialViewController.initGUI();
}
public RelativeLayout getRootRL(){
return mvRootRL;
}
public ViewFlipper getRootViewFlipper(){
return mvRootViewFlipper;
}
public View getMainView(){
return mvMainView;
}
public Activity getAct(){
return hAct;
}
public void setMainView(View v){
mvMainView = v;
}
public void setActivity(Activity a){
hAct = a;
}
public StringConverter getConverter(){
return mvConverter;
}
public void setConverter(StringConverter sc){
mvConverter = sc;
}
}
変換ビューコントローラー:
package cresco.ai.asciitobinstring.gui;
import cresco.ai.asciitobinstring.core.AsciiToBin_Main;
import cresco.ai.asciitobinstring.core.R;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
public class ConversionViewController extends View implements OnClickListener,
OnItemSelectedListener{
private AsciiToBin_Main hMain;
private LayoutInflater mvInflater;
private View mvConversionView;
private Button mvConvertB;
private Button mvToTutorialB;
private Spinner mvConversionTypeSP;
private EditText mvAsciiStringET;
private EditText mvBinStringET;
private ArrayAdapter<CharSequence> mvSpinnerAdapter;
public ConversionViewController(AsciiToBin_Main main) {
super(main.getAct());
hMain = main;
}
public void initGUI(){
mvInflater = (LayoutInflater)
hMain.getAct().getSystemService(hMain.getAct().LAYOUT_INFLATER_SERVICE);
mvConversionView = mvInflater.inflate(R.layout.conversion_layout,
hMain.getRootViewFlipper(),false);
hMain.getRootViewFlipper().addView(mvConversionView);
//hMain.getRootRL().addView(mvConversionView);
mvConvertB = (Button)hMain.getAct().findViewById(R.id.convertB);
mvToTutorialB =
(Button)hMain.getAct().findViewById(R.id.conversion_To_Tutorial_B);
mvAsciiStringET =
(EditText)hMain.getAct().findViewById(R.id.asciiStringET);
mvBinStringET = (EditText)hMain.getAct().findViewById(R.id.binStringET);
mvConversionTypeSP =
(Spinner)hMain.getAct().findViewById(R.id.conversionTypeSP);
mvConvertB.setOnClickListener(this);
mvToTutorialB.setOnClickListener(this);
mvConversionTypeSP.setOnItemSelectedListener(this);
}
public void initSpinnerElements(){
mvSpinnerAdapter = ArrayAdapter.createFromResource(hMain.getAct(),
R.array.conversion_choices_array, android.R.layout.simple_spinner_item);
mvSpinnerAdapter.setDropDownViewResource
(android.R.layout.simple_spinner_dropdown_item);
mvConversionTypeSP.setAdapter(mvSpinnerAdapter);
mvConversionTypeSP.setSelection(0);
//Now that that the UI is ready, display it
////hMain.getRootViewFlipper().showNext();
}
@Override
protected void onDraw(Canvas c){
super.onDraw(c);
}
@Override
public void onClick(View v) {
if(v==mvConvertB){
Log.d("me", "button pressed! Conversion type selected currently is
"+mvSpinnerAdapter.getItem(mvConversionTypeSP.getSelectedItemPosition()));
if(mvConversionTypeSP.getSelectedItemPosition() == 0){
//This is the convert ascii to binary string choice
//Calls the native method calculateBinFromAsciiStringJNI
//Not a terribly heavy process, but since it is disparate
//from
//the UI we should probably grant it its own thread...
//Uncomment when UI overlay bug is solved
new
NativeStringConversionTask(0).execute(mvAsciiStringET.getText().toString());
//mvBinStringET.setText(hMain.getConverter().
//calculateBinFromAsciiStringJNI(mvAsciiStringET
//.getText().toString())); //all on the UI thread, not good
}
else if(mvConversionTypeSP.getSelectedItemPosition() == 1){
//This is the convert binary to ascii string choice
//Uncomment when UI overlay bug is solved
new
NativeStringConversionTask(1).execute(mvBinStringET.getText().toString());
//mvAsciiStringET.setText(hMain.getConverter().
//calculateAsciiFromBinStringJNI(mvBinStringET
//.getText().toString())); //all on the UI thread. Not good
}
}
else if(v==mvToTutorialB){
//hMain.getRootViewFlipper().setDisplayedChild(1);
hMain.getRootViewFlipper().showNext();
//hMain.getAct().setContentView(R.layout.tutorial_layout);
}
}
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
Log.d("me", "itemselectedlistener received a callback! the position
selected is "+arg2);
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
Log.d("me", "itemselectedlistener received a no items slected callaback");
}
//Uncomment once the UI overlay issue is solved
private class NativeStringConversionTask extends AsyncTask<String,Integer,String>{
private int taskID = 0;
public NativeStringConversionTask(int id){
taskID = id;
}
@Override
protected void onPreExecute(){
Log.d("me","in the preExecute of the nativeStringConversion Async
task");
}
@Override
protected String doInBackground(String... s) {
//NB: if we wanted onProgressUpdate to be called with something we
//would
//invoke publishProgress(something) in this function
Log.d("me", "bg task started with taskID "+taskID);
if(taskID == 0){
publishProgress(taskID);
return
hMain.getConverter().calculateBinFromAsciiStringJNI(s[0].toString());
}
else if (taskID == 1){
publishProgress(taskID);
return
hMain.getConverter().calculateAsciiFromBinStringJNI(s[0].toString());
}
else{
publishProgress(taskID);
return "This shouldn't appear. if it does... may the
gods below help us all";
}
}
@Override
protected void onProgressUpdate(Integer... progress){
Log.d("me", "progressUpdate called!");
}
@Override
protected void onPostExecute(String result){
Log.d("me", "calling postExecute...");
if(taskID == 0){
mvBinStringET.setText((String)result);
}
else if (taskID == 1){
mvAsciiStringET.setText((String)result);
}
else{
mvBinStringET.setText("This shouldn't appear. if it
does... may the gods below help us all");
mvAsciiStringET.setText("This shouldn't appear. if it
does... may the gods below help us all");
}
//mvBinStringET.setText(s);
}
}
}
チュートリアルビューコントローラ:
package cresco.ai.asciitobinstring.gui;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import cresco.ai.asciitobinstring.core.AsciiToBin_Main;
import cresco.ai.asciitobinstring.core.R;
public class TutorialViewController extends View implements OnClickListener{
private AsciiToBin_Main hMain;
private LayoutInflater mvInflater;
private View mvTutorialView;
private Button mvToConversionB;
public TutorialViewController(AsciiToBin_Main main){
super(main.getAct());
hMain = main;
}
public void initGUI(){
mvInflater = (LayoutInflater)
hMain.getAct().getSystemService(hMain.getAct().LAYOUT_INFLATER_SERVICE);
mvTutorialView = mvInflater.inflate(R.layout.tutorial_layout,
hMain.getRootViewFlipper(),false);
hMain.getRootViewFlipper().addView(mvTutorialView);
mvToConversionB =
(Button)hMain.getAct().findViewById(R.id.tutorial_Conversion_B);
mvToConversionB.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v==mvToConversionB){
//hMain.getRootViewFlipper().setDisplayedChild(0);
hMain.getRootViewFlipper().showNext();
//hMain.getAct().setContentView(R.layout.conversion_layout);
}
}
}
StringConverter:
package cresco.ai.asciitobinstring.math;
import cresco.ai.asciitobinstring.core.AsciiToBin_Main;
public class StringConverter {
private AsciiToBin_Main hMain;
public StringConverter(AsciiToBin_Main main){
hMain = main;
}
//Uncomment once the UI overlay issue is solved
public native String calculateBinFromAsciiStringJNI(String s);
public native String calculateAsciiFromBinStringJNI(String s);
static {
System.loadLibrary("stlport_shared");
System.loadLibrary("ascii2bin");
}
}
Conversion_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="@+id/asciiStringET"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/conversionTypeSP"
android:layout_centerHorizontal="true"
android:layout_marginTop="71dp"
android:hint="Your ASCII string goes here"
android:text="" />
<EditText
android:id="@+id/binStringET"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/asciiStringET"
android:layout_below="@+id/asciiStringET"
android:layout_marginTop="61dp"
android:hint="Your binary string goes here"
android:text="" />
<Button
android:id="@+id/convertB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@+id/binStringET"
android:text="Convert Strings!" />
<Button
android:id="@+id/conversion_To_Tutorial_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@+id/convertB"
android:text="Read the tutorial on binary numbers" />
<Spinner
android:id="@+id/conversionTypeSP"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:layout_marginTop="57dp" />
</RelativeLayout>
tutorial_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/tutorial_Conversion_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="204dp"
android:text="Return to Conversion" />
</RelativeLayout>
Manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cresco.ai.asciitobinstring.core"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="cresco.ai.asciitobinstring.core.AsciiToBinActivity_Minimalist"
android:label="@string/app_name"
android:theme="@style/FullscreenTheme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
私が見ている結果は次のとおりです。
ここで不思議なのは、アプリをバックグラウンドに置いてから再度開くと(onPauseとonResumeが呼び出されるため)、読み込まれるUIが適切に更新され、古いビューアーティファクトが削除されることです。もちろん、edittextウィジェットのサイズを変更する新しい文字列変換を試みると、オーバーラップが再び作成されます。
誰かがこれの背後にあるかもしれないものを知っていますか?私はsdkリビジョン17、minSDKが8の標準ライブラリをターゲットにしています。これを最初に見たとき、これは新しいホロUIスキームの奇妙な副作用だと思ったので、styles.xmlを2.3準拠にロールバックしました。 UIスキームですが、改善は見られませんでした。何かを別々に台無しにした可能性があります...