0

私は、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>

私が見ている結果は次のとおりです。 UI_overlay UI_overlay2

ここで不思議なのは、アプリをバックグラウンドに置いてから再度開くと(onPauseとonResumeが呼び出されるため)、読み込まれるUIが適切に更新され、古いビューアーティファクトが削除されることです。もちろん、edittextウィジェットのサイズを変更する新しい文字列変換を試みると、オーバーラップが再び作成されます。

proper_view

誰かがこれの背後にあるかもしれないものを知っていますか?私はsdkリビジョン17、minSDKが8の標準ライブラリをターゲットにしています。これを最初に見たとき、これは新しいホロUIスキームの奇妙な副作用だと思ったので、styles.xmlを2.3準拠にロールバックしました。 UIスキームですが、改善は見られませんでした。何かを別々に台無しにした可能性があります...

4

1 に答える 1

0

そもそも何が起こったのかを確かに説明していないため、これ自体は実際には良い答えではありませんが、新しいプロジェクトを最初から作成すると、表示されていた奇妙なエラーが修正されることがわかりました。したがって、問題は UI スタイルをいじったことが原因である可能性が最も高いです... それよりも技術的な説明があればいいのにと思いますが、現時点ではありません。とにかく、他の誰かがこれに遭遇した場合は、プロジェクトを再作成すると問題が解決するようです. 誰かが追加したい説明の詳細がある場合は、お気軽に!

于 2013-01-14T16:00:31.040 に答える