0

我编写了一个相当简单的应用程序来提高我的 JNI 和多线程技能,它需要将一串 ascii 字符转换为二进制字符串或将二进制字符串转换为一个 ascii 字符串。每次转换背后的数学都是通过本机库处理的,并且每次调用本机代码都使用 AsyncTask 在其自己的线程上运行,以免破坏 UI。问题在于,当 UI 小部件需要更改大小或位置时,每当调用 onLayout 时,新图像都会放置在仍然可见的旧图像之上,而不是替换它。我尝试删除可能的罪魁祸首(JNI 模块、AsyncTask 模块),但即使它的功能被剥离并且只保留 UI,我也看到新 UI 视图重叠而不是替换旧视图的相同结果。从我下面的代码中可以看出,除了我现在活跃的更灵活的自定义 addView 模型之外,我还尝试了旧的 setContentView(...) 方法进行 UI 层次建模,但结果仍然相同。注意:这只发生在设备上(Nexus 7 运行最新的 4.2.1 和 Nexus S 运行 4.0.2);在模拟器中一切正常。这似乎与 GLES 调用有关,但我在这个应用程序中没有自己做任何事情,而且显然这不会发生在设备上的每个应用程序上,所以它看起来不像是操作系统问题...... 在模拟器中一切正常。这似乎与 GLES 调用有关,但我在这个应用程序中没有自己做任何事情,而且显然这不会发生在设备上的每个应用程序上,所以它看起来不像是操作系统问题...... 在模拟器中一切正常。这似乎与 GLES 调用有关,但我在这个应用程序中没有自己做任何事情,而且显然这不会发生在设备上的每个应用程序上,所以它看起来不像是操作系统问题......

活动课:

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);
    }
}

}

字符串转换器:

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");
    }

}

转换布局.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>

清单.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 小部件大小的新字符串转换会再次创建重叠。

正确视图

有谁知道这背后可能是什么?我的目标是 sdk 修订版 17,minSDK 为 8 的标准库。当我第一次看到这个时,我认为这是新的全息 UI 方案的奇怪副作用,所以我将 styles.xml 回滚到 2.3 兼容UI 方案,但我没有看到任何改进。可能是单独搞砸了一些东西......

4

1 回答 1

0

这本身并不是一个很好的答案,因为它当然不能解释首先发生的事情,但我发现从头开始创建一个新项目可以解决我看到的奇怪错误;因此,这个问题很可能是由于我对 UI 样式的混乱造成的……希望我有比这更技术性的解释,但目前我没有。无论如何,如果其他人遇到这种情况,重新创建您的项目似乎可以解决问题。如果有人想添加更多解释性细节,请随意!

于 2013-01-14T16:00:31.040 回答