分类 技术 下的文章

Nginx反向代理慢解决办法

在配置nginx反向代理时upstream里面server用localhost:端口,非常慢,看log,默认将localhost解析成ipv6的地址,故出现此问题,改成127.0.0.1后问题解决。
后端被代理网络应用使用Delphi开发

Get process name in Android

public static String getProcessName() {
  try {
    File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
    BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
    String processName = mBufferedReader.readLine().trim();
    mBufferedReader.close();
    return processName;
  } catch (Exception e) {
    e.printStackTrace();
    return null;
  }
}

JAVA神奇又强大的反射

最近在写安卓项目的时候遇到一个很棘手的问题,AsyncTask的某一个task似乎被前一个task卡住了很久,应该是之前的task执行了一些非常耗时的操作,使得后面的task一直被卡住。查看源码后发现那个代码中用的是execute()方法而不是executeOnExecutor,所以使用的是默认的SERIAL_EXECUTOR,我理所当然地认为是某个地方使用了SERIAL_EXECUTOR然后用时太长导致后面的task都被卡住,所以把项目里用execute的地方都改成了executeOnExecutor,发现问题没解决。苦于没有解决办法,拖了几天没看。今天再去看代码的时候神奇的发现SERIAL_EXECUTOR使用的居然也是THREAD_POOL_EXECUTOR,只不过内部做了一个serial处理,我就更加疑惑了,怎么用了线程池还会被卡住呢。。。

我就在想,如果有什么办法可以在THREAD_POOL_EXECUTOR执行execute的方法的时候printStackTrace一下就好了,然后突发其想能不能利用java的反射原理把AsyncTask的THREAD_POOL_EXECUTOR替换成我自己的,这样我就可以打log了,上网搜索了一下,果然可以,真是太强大了。

打log发现是一个第三方sdk用AsyncTask来执行网络连接,然后很长时间都没能连到服务器,导致被卡住,真是。。。所幸问题找到了,去掉那个库问题果然解决了。Java反射真是强大

不过,我在打log的时候惊奇的发现,THREAD_POOL_EXECUTOR在我手机上只开了一个线程,很奇怪,按理说不应该这样的。。。留到后面再看看是咋回事吧

在Application初始化的时候

MyExecutor executor = new MyExecutor();
    try {
      Field field = AsyncTask.class.getField("THREAD_POOL_EXECUTOR");
      field.setAccessible(true);
      field.set(null, executor);
    } catch (Exception e) {
      Log.e("MyAsyncTask","exception when using reflection");
    }

自己写的Executor

public static class MyExecutor extends ThreadPoolExecutor {

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
      private final AtomicInteger mCount = new AtomicInteger(1);

      public Thread newThread(Runnable r) {
        return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
      }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

    public MyExecutor() {
      super(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
          sPoolWorkQueue, sThreadFactory);
      allowCoreThreadTimeOut(true);
    }

    @Override public void execute(Runnable command) {
      if (command != null) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        new Throwable().printStackTrace(pw);
        Log.d("MyAsyncTask", sw.toString());
      }
      super.execute(command);
    }
  }

Handle uncaught exception in Android app

  1. Handle uncaughtException in your Application subclass.
  2. After catching an exception, start a new activity to ask the user to send a log.
  3. Extract the log info from logcat's files and write to your own file.
  4. Start an email app, providing your file as an attachment.
  5. Manifest: filter your activity to be recognized by your exception handler.
  6. Optionally, setup Proguard to strip out Log.d() and Log.v().
public class MyApplication extends Application
{
  public void onCreate ()
  {
    // Setup handler for uncaught exceptions.
    Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
    {
      @Override
      public void uncaughtException (Thread thread, Throwable e)
      {
        handleUncaughtException (thread, e);
      }
    });
  }

  public void handleUncaughtException (Thread thread, Throwable e)
  {
    e.printStackTrace(); // not all Android versions will print the stack trace automatically

    Intent intent = new Intent ();
    intent.setAction ("com.mydomain.SEND_LOG"); // see step 5.
    intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); // required when starting from Application
    startActivity (intent);

    System.exit(1); // kill off the crashed app
  }
}
private String extractLogToFile()
{
  PackageManager manager = this.getPackageManager();
  PackageInfo info = null;
  try {
    info = manager.getPackageInfo (this.getPackageName(), 0);
  } catch (NameNotFoundException e2) {
  }
  String model = Build.MODEL;
  if (!model.startsWith(Build.MANUFACTURER))
    model = Build.MANUFACTURER + " " + model;

  // Make file name - file must be saved to external storage or it wont be readable by
  // the email app.
  String path = Environment.getExternalStorageDirectory() + "/" + "MyApp/";
  String fullName = path + <some name>;

  // Extract to file.
  File file = new File (fullName);
  InputStreamReader reader = null;
  FileWriter writer = null;
  try
  {
    // For Android 4.0 and earlier, you will get all app's log output, so filter it to
    // mostly limit it to your app's output.  In later versions, the filtering isn't needed.
    String cmd = (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) ?
                  "logcat -d -v time MyApp:v dalvikvm:v System.err:v *:s" :
                  "logcat -d -v time";

    // get input stream
    Process process = Runtime.getRuntime().exec(cmd);
    reader = new InputStreamReader (process.getInputStream());

    // write output stream
    writer = new FileWriter (file);
    writer.write ("Android version: " +  Build.VERSION.SDK_INT + "\n");
    writer.write ("Device: " + model + "\n");
    writer.write ("App version: " + (info == null ? "(null)" : info.versionCode) + "\n");

    char[] buffer = new char[10000];
    do 
    {
      int n = reader.read (buffer, 0, buffer.length);
      if (n == -1)
        break;
      writer.write (buffer, 0, n);
    } while (true);

    reader.close();
    writer.close();
  }
  catch (IOException e)
  {
    if (writer != null)
      try {
        writer.close();
      } catch (IOException e1) {
      }
    if (reader != null)
      try {
        reader.close();
      } catch (IOException e1) {
      }

    // You might want to write a failure message to the log here.
    return null;
  }

  return fullName;
}
public class SendLog extends Activity implements OnClickListener
{
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    requestWindowFeature (Window.FEATURE_NO_TITLE); // make a dialog without a titlebar
    setFinishOnTouchOutside (false); // prevent users from dismissing the dialog by tapping outside
    setContentView (R.layout.send_log);
  }
}
<activity
    android:name="com.mydomain.SendLog"
    android:theme="@android:style/Theme.Dialog"
    android:textAppearance="@android:style/TextAppearance.Large"
    android:windowSoftInputMode="stateHidden">
    <intent-filter>
      <action android:name="com.mydomain.SEND_LOG" />
      <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
-assumenosideeffects class android.util.Log {
    public static int v(...);
    public static int d(...);
}