- 浏览: 284795 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (142)
- android (64)
- android team 应用开发流程 (0)
- android 个人 开发流程 (1)
- android UI 切换皮肤 (1)
- java (9)
- 敏捷开发 (1)
- git (1)
- 学习 (2)
- hibernate (0)
- jQuery (1)
- windows (2)
- tomcat (1)
- Spring (3)
- struts2 (5)
- mysql (4)
- linux (15)
- JBPM (2)
- maven (4)
- 企业管理 (1)
- Iphone (1)
- 工作计划 (0)
- news (1)
- MOVE (1)
- exception-android (1)
- RFID (1)
- 测试 (7)
- android基础 (1)
- Gson (1)
- Android中的单元测试 (1)
最新评论
-
jlees:
Nice post.i hope this will help ...
Business mobile application development. The developer’s insight. -
weisi2375:
确实很详细的开发流程。
Android应用开发全流程 -
mikefather:
不错不错
Android,谁动了我的内存 -
ylzyd12345:
mark一下,谢谢分享
android的一些开源项目 -
limingcai:
确实不行,2.2就不行了,虽说2.3了 只有1.6可以
Android完全关闭应用程序
链接地址收藏 http://www.vogella.de/articles/AndroidPerformance/article.html
1. Overview
Android modifies the user interface via one thread, the UI Thread. If the programmer does not use any concurrency constructs, all code of an Android application runs in this UI thread. If you perform a long lasting operation the user interface of your Android Application will block until your code has finished.
This is especially important as Android will display an "Application not responding" (ANR) dialog if an activities does not react within 5 seconds. From this dialog the user can choose to stop the application.
Therefore all potentially slow running operations in an Android application should run in the background, e.g. via some way of concurrency constructs of the Java language or the Android framework. Potential slow operations are network, file and database access but also complex calculations.
This tutorial will teach how to use the special Android constructs for concurrency.
The following assumes that you have already basic knowledge in Android development . Please check the Android development tutorial to learn the basics.
Android supports standard Java Threads . You can use standard Threads and the tools from the package "java.util.concurrent" to put actions into the background. The only limitation is that you cannot directly update the UI from the a background process. See Java Concurrency Tutorial for an introduction into background processing with standard Java.
If you need to update the UI from a background task you need to use some Android specific classes. You can use the class "android.os.Handler" for this or the class "AsyncTasks".
The class "Handler" can update the UI. A handle provides methods for receiving messages and for runnables. To use a handler you have to subclass it and overide handleMessage() to process messages. To process runables you can use the method post(); You only need one instance of a handler in your activity.
You thread can post messages via the method sendMessage(Message msg) or sendEmptyMessage.
The class AsyncTask encapsulates the creation of Threads and Handlers. You must implement the method "doInBackground()", which defines what action should be done in the background. This method is be automatically run in a separate Thread. To update the UI you can override the method "onPostExecute()". This method will be called by the framework once your action is done and runs within the UI thread. AsyncTask
To use AsyncTask you must subclass it. AsyncTask uses generics and varargs.The parameters are the following AsyncTask <TypeOfVarArgParams , ProgressValue , ResultValue> . TypeOfVarArgParams is passed into the doInBackground(), ProgressValueis used for progress information and ResultValue must be returned from doInBackground() and is passed to onPostExecute() as parameter.
For providing feedback to the user you can use the view "ProgressBar" which allow to display progress to the user. The Javadoc of "ProgressBar" gives a nice example of its usage.
Alternatively you can provide progress feedback in the activities title bar.
One challenge in using threads is to consider the lifecycle of the application . The Android system may kill your activity or trigger a configuration change which also will restart your activity.
You also need to handle open dialogs, as dialogs are always connected to the activity which created them. In case the activity gets restarted and you access an existing dialog you receive an "View not attached to window manager" exception.
To save an object your can use the method onRetainNonConfigurationInstance() and to retrieve this object getLastNonConfigurationInstance(). This way can you can save a running thread even if the activity is restarted. getLastNonConfigurationInstance() returns null if the activity is started the first time of if the it has been finished via the finish() method.
If more then one object should be saved then you can implement the class "Application". This class can be used to access object which should be cross activities or available for the whole application lifecycle. In the onCreate() and onTerminate() you can create / destroy the object and make them available via public fields or getters. To use your application class assign the classname to the android:name attribute of your application.
<application android:icon="@drawable/icon" android:label="@string/app_name"
android:name="MyApplicationClass">
<activity android:name=".ThreadsLifecycleActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
You can acess the Application via the getApplication() method in your activity.
In this example we use the class "Handler" to update a ProgressBar in a background thread.
Create a new Android project "de.vogella.android.handler" with the activity "ProgressTestActivity". Create the following layout "main.xml". This layout contains the ProgressBar and sets its appearance via a style.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ProgressBar android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent"
android:layout_height="wrap_content" android:indeterminate="false"
android:max="10" android:padding="4dip"></ProgressBar>
<Button android:text="Start Progress" android:onClick="startProgress"
android:id="@+id/button1" android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
</LinearLayout>
Change your activity to the following:
package de.vogella.android.handler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ProgressBar;
public class ProgressTestActivity extends Activity {
private Handler handler;
private ProgressBar progress;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
progress = (ProgressBar) findViewById(R.id.progressBar1);
handler = new Handler();
}
public void startProgress(View view) {
// Do something long
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
@Override
public void run() {
progress.setProgress(value);
}
});
}
}
};
new Thread(runnable).start();
}
}
Run your application. Once you press your button the ProgressBar will get updated from the background thread.
In this example we will use AsyncTask to download the content of a webpage. We use Android HttpClient for this. Create a new Android project "de.vogella.android.asynctask" with the activity "ReadWebpageAsyncTask". Add the permission "android.permission.INTERNET". Create the following layout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/readWebpage" android:onClick="readWebpage" android:text="Load Webpage"></Button>
<TextView android:id="@+id/TextView01" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Example Text"></TextView>
</LinearLayout>
Change your activity to the following:
package de.vogella.android.asynctask;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class ReadWebpageAsyncTask extends Activity {
private TextView textView;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.TextView01);
}
private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
@Override
protected void onPostExecute(String result) {
textView.setText(result);
}
}
public void readWebpage(View view) {
DownloadWebPageTask task = new DownloadWebPageTask();
task.execute(new String[] { "http://www.vogella.de" });
}
}
If you run your application and press your button then the content of the defined webpage should be read in the background. Once this process is done your TextView will be updated.
The following example will download an image from the Internet in a thread and displays a dialog until the download is done. We will make sure that the thread is preserved even if the activity is restarted and that the dialog is correctly displayed and closed.
For this example create the Android project "de.vogella.android.threadslifecycle" and the Activity "ThreadsLifecycleActivity". Also add the the permission to use the Internet to your app. Details for this can found here: Networking with Android .
You should have the following AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.threadslifecycle" android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".ThreadsLifecycleActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Change the layout "main.xml" to the following.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:layout_height="wrap_content"
android:layout_width="match_parent" android:id="@+id/linearLayout1">
<Button android:onClick="downloadPicture"
android:layout_height="wrap_content" android:text="Click to start download"
android:layout_width="wrap_content"></Button>
<Button android:onClick="resetPicture" android:layout_height="wrap_content"
android:text="Reset Picture"
android:layout_width="wrap_content"></Button>
</LinearLayout>
<ImageView android:src="@drawable/icon" android:id="@+id/imageView1"
android:layout_height="match_parent" android:layout_width="match_parent"></ImageView>
</LinearLayout>
Now adjust your activity. In this activity the thread is saved and the dialog is closed if the activity is destroyed.
package de.vogella.android.threadslifecycle; import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import android.app.Activity; import android.app.ProgressDialog; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.ImageView; public class ThreadsLifecycleActivity extends Activity { // Static so that the thread access the latest attribute private static ProgressDialog dialog; private static ImageView imageView; private static Bitmap downloadBitmap; private static Handler handler; private Thread downloadThread; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Create a handler to update the UI handler = new Handler(); // get the latest imageView after restart of the application imageView = (ImageView) findViewById(R.id.imageView1); // Did we already download the image? if (downloadBitmap != null) { imageView.setImageBitmap(downloadBitmap); } // Check if the thread is already running downloadThread = (Thread) getLastNonConfigurationInstance(); if (downloadThread != null && downloadThread.isAlive()) { dialog = ProgressDialog.show(this, "Download", "downloading"); } } public void resetPicture(View view) { if (downloadBitmap != null) { downloadBitmap = null; } imageView.setImageResource(R.drawable.icon); } public void downloadPicture(View view) { dialog = ProgressDialog.show(this, "Download", "downloading"); downloadThread = new MyThread(); downloadThread.start(); } // Save the thread @Override public Object onRetainNonConfigurationInstance() { return downloadThread; } // dismiss dialog if activity is destroyed @Override protected void onDestroy() { if (dialog != null && dialog.isShowing()) { dialog.dismiss(); dialog = null; } super.onDestroy(); } // Utiliy method to download image from the internet static private Bitmap downloadBitmap(String url) throws IOException { HttpUriRequest request = new HttpGet(url.toString()); HttpClient httpClient = new DefaultHttpClient(); HttpResponse response = httpClient.execute(request); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); if (statusCode == 200) { HttpEntity entity = response.getEntity(); byte[] bytes = EntityUtils.toByteArray(entity); Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); return bitmap; } else { throw new IOException("Download failed, HTTP response code " + statusCode + " - " + statusLine.getReasonPhrase()); } } static public class MyThread extends Thread { @Override public void run() { try { // Simulate a slow network try { new Thread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } downloadBitmap = downloadBitmap("http://www.vogella.de/img/lars/LarsVogelArticle7.png"); handler.post(new MyRunnable()); } catch (IOException e) { e.printStackTrace(); } finally { } } } static public class MyRunnable implements Runnable { public void run() { imageView.setImageBitmap(downloadBitmap); dialog.dismiss(); } } }
Run your application and press the button to start a download. You can test the correct lifecycle behavior in the emulator via pressing "CNTR+F11" as this changes the orientation.
It is important to note that the Thread is a static inner class. It is important to use a static inner class for your background process because otherwise the inner class will contain a reference to the class in which is was created. As the thread is passed to the new instance of your activity this would create a memory leak as the old activity would still be referred to by the Thread.
StrictMode is available as of API 9, therefore make sure to use Android 2.3.3. As discussed you should avoid performing long running operations on the UI thread. This includes file and network access. It is sometimes difficult to remember to make all the right things in your application during development. That is were StrictMode comes in. It allows to setup policies in your application to avoid doing incorrect things. For example the following setup will crash your application if it violates some of the Android policies. StrictMode should only be used during development and not in your live application.
Create for example "de.vogella.android.strictmode" with the activity "TestStrictMode". The following will set strict rules for your application. As the activity violates these settings you application will crash.
package de.vogella.android.strictmode;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import android.app.Activity;
import android.os.Bundle;
import android.os.StrictMode;
public class TestStrictMode extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll().penaltyLog().penaltyDeath().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
.penaltyLog().penaltyDeath().build());
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String eol = System.getProperty("line.separator");
try {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
openFileOutput("myfile", MODE_WORLD_WRITEABLE)));
writer.write("This is a test1." + eol);
writer.write("This is a test2." + eol);
writer.write("This is a test3." + eol);
writer.write("This is a test4." + eol);
writer.write("This is a test5." + eol);
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Traceview is a graphical viewer to see logs created by an Android application. Via Traceview you can find errors in your application and measure its performance.
Eclipse supports tracing directly in the DDMS perspective. In the devices view select your application process and select "Start Method Profiling".
Use your application and re-press the same button to stop profiling. This will open a new editor which shows you the result of traceview.
You can zoom into the graphic to get more details.
To start tracing some code put the following code snippet around it.
android.os.Debug.startMethodTracing("yourstring");
// ... your code is here
android.os.Debug.stopMethodTracing();
The parameter "yourstring" tells the system that it should store the data under "/sdcard/yourstring.trace". To save data on the sdcard your application needs the WRITE_EXTERNAL_STORAGE permission. After running your application you can use Traceview via adb .
adb pull /sdcard/yourstring.trace
traceview yourstring
This will start Traceview which allow you to analyse your performance data via a graphical way. The DDMS view has also a trace button available. This will trace the running application and does not require an additional authorization.
You can create a memory snapshot and analyse it with the Eclipse Memory Analyzer .
Before posting questions, please see the vogella FAQ . If you have questions or find an error in this article please use the www.vogella.de Google Group . I have created a short list how to create good questions which might also help you.
Eclipse RCP Training (German) Eclipse RCP Training with Lars Vogel
Android Tutorial Introduction to Android Programming
GWT Tutorial Program in Java and compile to JavaScript and HTML
Eclipse RCP Tutorial Create native applications in Java
JUnit Tutorial Test your application
Git Tutorial Put everything you have under distributed version control system
发表评论
-
Resource-type-->Color State List Resource
2013-04-22 10:50 1679Color State List Resource Col ... -
Business mobile application development. The developer’s insight.
2012-11-07 17:49 1651from: http://www.enterra-inc.co ... -
Android. Handling some SQLite issues.
2012-11-07 17:48 1787转载: http://www.enterra-inc.com/ ... -
git 获取android source
2012-08-15 12:52 3685在做android开发的时,在遇到某一问题,想看andro ... -
Android 手机上获取物理唯一标识码
2012-07-27 10:27 11776唯一标识码这东西在网络应用中非常有用,例如检测是否 ... -
android listview adapter
2012-06-23 14:41 1021listview 在什么情况下会刷新: 1. 当ada ... -
Android多线程下载详解
2012-06-20 18:31 944http://www.pin5i.com/showtopic- ... -
Unable to open sync connection!
2012-06-18 17:04 971把设置里的USB调试重新开了开,问题解决! -
android checkbox 定制(修改checkbox 的图片)
2012-06-18 14:30 3654转载:http://www.bangchui.org/read ... -
Android ProgressBar自定义图片进度,自定义渐变色进度条
2012-06-15 16:53 7594 -
Android应用开发全流程
2012-06-15 09:21 3783转载:http://blog.csd ... -
intent.setDataAndType
2012-06-13 18:24 74991. Intent open a picture ... -
Android操作HTTP实现与服务器通信
2012-06-03 14:47 1747本示例以Servlet为例,演示Android与Serv ... -
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thre
2012-06-03 12:00 9042当应用程序启动,创建了一个叫“main”的线程,用于管理 ... -
这篇文章是android开发人员的必备知识,是我特别为大家整理和总结的,不求完美,但是有用。 1.签名的意义 为了保证每个应用程序开发商合法ID,防止部分开
2012-05-25 13:58 1530这篇文章是android开发人员的必备知识,是我特别为大 ... -
android Collections.sort(List<T> list) 与JAVA Collections.sort(List<T> list)
2012-05-04 10:33 1863Info.java : public class In ... -
android string xliff:g
2012-03-22 10:47 1021这个主要用于程序中,动态的插入内容时候使用,例如, ... -
android的一些开源项目
2011-12-07 17:13 2172转自: http://www.uuroid.com ... -
Understanding the Android Build Process
2011-11-25 12:38 982http://www.alittlemadness.com/2 ... -
Android 命令行手动编译打包详解
2011-11-24 10:07 1249Android 命令行手动编译打包过程图 【详细步骤】: 1 ...
相关推荐
This tutorial explores the basics of threads -- what they are, why they are useful, and how to get started writing simple programs that use them. We will also explore the basic building blocks of more...
赠送jar包:jboss-threads-3.1.0.Final.jar; 赠送原API文档:jboss-threads-3.1.0.Final-javadoc.jar; 赠送源代码:jboss-threads-3.1.0.Final-sources.jar; 赠送Maven依赖信息文件:jboss-threads-3.1.0.Final....
本教程探索线程的基础知识 - 它们是什么,为什么它们是有用的,以及如何开始写以及使用这些简单的程序,同时探讨更复杂的线程应用程序的基本构件 - 如何在线程之间的数据交换,如何控制线程以及线程之间如何相互通信...
离线安装包,亲测可用
本文将深入探讨标题所提及的三个实用脚本:“show-busy-java-threads”、“show-duplicate-java-classes”以及“find-in-jars”。这些脚本都是针对Java开发者和系统管理员的利器,旨在提高效率和解决问题。 1. **...
python库。 资源全名:Flask_Threads-0.0.1a0-py3.6.egg
赠送jar包:jboss-threads-3.1.0.Final.jar; 赠送原API文档:jboss-threads-3.1.0.Final-javadoc.jar; 赠送源代码:jboss-threads-3.1.0.Final-sources.jar; 赠送Maven依赖信息文件:jboss-threads-3.1.0.Final....
`show-busy-java-threads.sh`脚本就是为了帮助开发者快速定位和排查这类性能问题而设计的。这个脚本主要用于监控并展示Java应用程序中的繁忙线程,从而帮助我们理解程序的执行状态,找出可能导致高CPU负载的原因。 ...
离线安装包,亲测可用
"worker-threads-pool" 是一个专门为Node.js设计的库,它的目的是简化工作线程池的管理和操作。工作线程池可以有效地将CPU密集型任务分配到不同的工作线程中,从而提高程序的执行效率。这个库的主要功能包括创建...
a tutorial on how to implement and optimize mutexes with gcc inline assembly
在计算机科学中,线程(Threads)和进程(Processes)是操作系统中两个基本且重要的概念,它们对于理解和优化软件性能至关重要。线程是程序执行的最小单元,而进程则是资源分配的基本单位。让我们深入探讨这两个概念...
vulapp VULAPP] [--lhost LHOST] [--lport LPORT] [--rhost RHOST] [--rport RPORT]SSRF Explotion Toolsoptional arguments: -h, --help show this help message and exit --url URL Input the url u want to ...
AndBug -- A Scriptable Android Debugger AndBug is a debugger targeting the Android platform's Dalvik virtual machine intended for reverse engineers and developers. It uses the same interfaces as ...
`info threads`列出所有活动线程,`thread <thread id>`切换到指定线程,而`bt full`会显示包含线程信息的完整回溯。 GDB还有许多其他高级特性,比如命令脚本、自动完成、用户定义的命令和函数。通过编写`.gdbinit`...
A self-contained reference that relies on the latest UNIX standards,UNIX Systems Programming provides thorough coverage of files, signals,semaphores, POSIX threads, and client-server communication....
rpm安装包,rpm -i example.rpm