Skip to content

Latest commit

 

History

History
375 lines (256 loc) · 10.2 KB

android_dev_tips.md

File metadata and controls

375 lines (256 loc) · 10.2 KB

android dev tips

open browser

import android.content.Intent ;
import android.net.Uri ;

public  static void openAppStore(  final String url ) {
    Intent viewIntent = new Intent(Intent.ACTION_VIEW,Uri.parse( url ));  
    // "android.intent.action.VIEW"
    mContext.startActivity(viewIntent);
}

whole-archieve prebuilt static library

  • use LOCAL_WHOLE_STATIC_LIBRARIES instead of LOCAL_STATIC_LIBRARIES

whether is Main thread ?

import android.os.Looper ;
public static boolean isMainThread() {
    return Looper.getMainLooper().getThread() == Thread.currentThread();
}

prevent background app auto close

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // prevent auto restarting rather than resuming
        // on some android device
        if (!isTaskRoot()
                && getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)
                && getIntent().getAction() != null
                && getIntent().getAction().equals(Intent.ACTION_MAIN)) {

            finish();
            return;
        }
        ...

Run on UI thread

	    mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText( mActivity , str, Toast.LENGTH_SHORT ).show();
            }
        });

run on working thread

  • more details : Cocos2dxHelper
    private static Handler mWorkingHandler = null  ;
    private static Thread mWorkingThread = null;

    // should be initially called by working thread
    public static void setWorkingThread() {
        if ( mWorkingThread == null )
            mWorkingThread = Thread.currentThread(); 
    }
    public static void runOnWorkingThread( Runnable action ) {
        if ( mWorkingThread == null )
            return ;

        if ( mWorkingHandler == null ) {
            // Default constructor associates this handler with the Looper for the current thread.
            mWorkingHandler = new Handler() ;
        }

        if (Thread.currentThread() != mWorkingThread) {
             mWorkingHandler.post(action);
         } else {
             action.run();
         }

    }

Using Gson

gson

in your app level build.gradle

dependencies {
  implementation 'com.google.code.gson:gson:2.2.1'
}

using in your android project

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.HashMap;

/**
 * This class provides basic/common functionalities to be applied on Java Objects.
//*/
public final class ObjectUtils {

    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();

    private ObjectUtils() {
         throw new UnsupportedOperationException("Instantiation of this class is not permitted in case you are using reflection.");
    }

    /**
     * This method is responsible for de-serializing the Java Object into Json String.
     *
     * @param object Object to be de-serialized.
     * @return String
     */
    public static String deserializeObjectToString(final Object object) {
        return GSON.toJson(object);
    }
    public static HashMap<String,Object> json2map( String json )  {
            HashMap<String,Object> map = new HashMap<String,Object>();
            map = (HashMap<String,Object>) GSON.fromJson(json, map.getClass());
            return map ;
    }
}

to use:

import com.google.gson.internal.StringMap;
...

     HashMap<String,Object> map = ObjectUtils.json2map(  response.toString() );
    StringMap<String> ret_data = (StringMap<String>)map.get( "data" );

AsyncTask

  • This class was deprecated in API level 30.
  • Use the standard java.util.concurrent or Kotlin concurrency utilities instead.
 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     // invoked on the UI thread before the task is executed. 
     // This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
    protected void onPreExecute() {
        super.onPreExecute();
        Log.d(TAG + " PreExceute","On pre Exceute......");
    }

     // invoked on the background thread immediately after onPreExecute() finishes executing. 
     // The parameters of the asynchronous task are passed to this step.
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);

             // This step can also use publishProgress(Progress...) to publish one or more units of progress. 
             // These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         // invoked on the UI thread after a call to publishProgress(Progress...).
         // This method is used to display any form of progress in the user interface while the background computation is still executing.
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         // invoked on the UI thread after the background computation finishes.
         // The result of the background computation is passed to this step as a parameter.
         showDialog("Downloaded " + result + " bytes");
     }
 }
 

Once created, a task is executed very simply:

 new DownloadFilesTask().execute(url1, url2, url3);

sometime you just want to do some simple test, and don't care about whether AsyncTask will freeze the UI thread ...

TYPE ret = new DownloadFilesTask().execute(url1, url2, url3).get() ;

Update Eclipse project to ant

android update project -p . -t android-23
ant debug

How to determine ABI of Android .so file

# just for example, using NDK r20
$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-readelf -A <.so file>

Find dependency of android shared library

$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-readelf  -d ../dist/Android/libs/armeabi-v7a/libgo.so

TODO ...


Android App Quich Start

Layer VS. Activity

A layout is made up of definitions written in XML. Each definition is used to create an object that appears on screen, like a button or some text.

An activity is the java code which attaches actions and puts content to/in a layout.

For this the Activity loads the layout.

This is how layouts gets connected to our activity.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // connect layout to activity
        // activity_main.xml is the layout XML file
        setContentView(R.layout.activity_main)
    }
}

Constraint Layout

When we're putting some views inside of another view, the Constraint Layout is called out.

Constraint Layout lets us position the sub-views by using constraints, which makes creating a layout super simple.

You can drag the white circle to edge of the screen to make the connection.

View ID

Each view has it's own ID. sometimes you'd better to rename the default ID to a meaningful name.

We can access any view by its ID.

import android.widget.Button
...
    setContentView(R.layout.activity_main)

    // PS. Must invoke findViewById after `setContentView` finish

    val rollButton = findViewById<Button>( R.id.rollButton )
    val resultsTextView = findViewById<TextView>(  R.id.resultTextView )
    val seekBar = findViewById<SeekBar>(R.id.seekBar2)

Add Listener

    rollButton.setOnClickListener {
        Log.d( "MyApp", "roll dice" )
        val rand = Random().nextInt( seekBar.progress + 1 )
        resultsTextView.text = rand.toString()
    }