❶ Android開發之路-多線程
多線程作為Android開發中相對而言較為高階的知識,其中用到相關的知識點是非常的多,所以在我們需要進行設計或者寫多線程的代碼就必須要進行相對謹慎的處理,這樣就由必要對其要有著比較系統化的認知
我們一般將Android應用分成為兩種:主線程和工作線程;主線程主要是用來進行初始化UI,而工作線程主要是進行耗時操作,例如讀取資料庫,網路連接等
Android系統是以進程為單位來對應用程序資源進行限制,這個問題的可以解釋為:一個進程最多能夠開幾個線程?最好能開幾個?但實則這個是沒有上限這一說,主要是因為資源的限制
Android中關於主線程的理解:Android的主線程是UI線程,在Android中,四大組件運行在主線程中,在主線程中做耗時操作會導致程序出現卡頓甚至出現ANR異常,一個.
在一個程序中,這些獨立運行的程序片斷叫作「線程」(Thread),利用它編程的概念就叫作「多線程處理」。多線程處理一個常見的例子就是用戶界面。
線程總的來就是進程的一個實體,是CPU進行分派和調度的基本單位,擁有著比進程更小且能夠獨立運行的基本單位,線程本身基本上是不擁有系統資源,僅擁有一點在運行過程中必須擁有的資源,但它可與同屬一個進程中的其他進程進行共享其所擁有的所有資源
線程狀態有些地方將之分為5中狀態,而且在java Jdk中線程被其定義為6中狀態,我們可以對其進行類比
普遍定義的5中狀態:新建,就緒,運行,阻塞, 死亡
Java Jdk 定義狀態
線程阻塞是指在某一時刻的某一個線程在進行運行一段代碼的情況下,突然另一個線程也要進行運行,但在運行過程中,那個線程執行完全運行之前,另一個線程是不可能獲取到CPU的執行權,就會導致線路阻塞的出現
死鎖也稱之為抱死,意思就是說一個進程鎖定了另外一個進程所需要的頁或表是,但第二個進程同時又鎖定了第一個進程所需的一頁,這樣就會出現死鎖現象
簡要介紹實現線程的三種方式:繼承Thread,實現runnable,實現callable。這里有一點需要注意的是,實現callable是與線程池相關聯的而callable很重要的一個特性是其帶有返回值。當我們只需實現單線程時實現runnable更加利於線程程序的拓展
在線程開啟之前進行調用 thread.setDaemon(true); 將thread設定成當前線程中的守護線程 使用案例
線程讓步【yield方法】讓當前線程釋放CPU資源,讓其他線程搶占
這種具體某個對象鎖 wait & notify 方法與Condition 的 await以及signal方法類似; 全面這種方法的阻塞等待都可以是釋放鎖,而且在喚醒後,這種線程都是能夠獲取鎖資源的,而這個門栓就跟閥門類似
❷ android-Service和Thread的區別
Service 是 Android 中四大組件之一,在 Android 開發中起到非常重要的作用。
Service(服務)是一個沒有用戶界面的在後台運答行賣行執行「耗時操作」的應用組件。其
他應用組件能夠啟勱 Service,並且當用戶切換到另外的應用場景,Service 將持續在
後台運行。另外,一個組件能夠綁定到一個 service 與之交互(IPC 機制),例如,一
個 service 可能會處理網路操作,播放音樂,操作文件 I/O 戒者不內容提供者
(content provider)交互,所有這些活動都是在後台進行。
關鍵它是有生命周期。
service用法:
(1)創建一個類繼承service
(2)在清單文件中去注冊
(3)開始使用
Thread簡介:
1.由於線程是依賴進程而存在的,所以我們應該先創建一個進程出來。但是進程是由系統創建的,所以我們需要帶虧調用系統功能創建一個進程。但是Java不具備直接調用系統功能的能力,所以,我們沒辦法直接實現多線程程序。
然而,Java可以直接去調用C/C++寫好的程序來實現多線程程序。再由C/C++去調用系統功能創建進程,然後由Java去調用這樣的東西。所以,Java提供能實現多線程的底層類庫。例如:Thread類。
2.生命周期:任何線程(包括主線程:main線程)在其生命周期中,都有5中狀態:創建、就緒、運行、阻塞、終止。
3.多線程實現:
(1)實現線程的方式一:
1.自定義一個類 ,繼承Thread類
2.自定義類中重寫Thread的run方法
3.創建自定義類對象
4.啟動線程
(2)實現線程的方式二:
實現Runnable介面:
1.自定義類實現Runnable介面
2.在自定義清逗類中實現run方法
3.創建自定義類對象
4.創建Thread類對象,並且將自定義類中的對象當做構造參數傳遞
5.啟動線程
❸ 如何解決空指針異常和 ThreadException 中的錯誤android
空指針異常: 可以直接在可差洞唯能出現空指針的代碼處 try catch一下,你也可以這樣做:在用到可能出現空指針的 變數或者對象處,先增加一個判空顫亂處理(比如:if(textutil.isempty(str) { })
對於ThreadException:對於線程的異常,在android中,google禁止了在主線程中進行訪問網路等一些耗時操作(否則就會出現這種異常)。可以開個子虛培線程(workThread)在裡面進行訪問網路,用非同步任務或者 handler來處理。
❹ 程序Android中Handler和Timer還有Thread的最大區別是什麼
我個人覺得thread是者禪用來後台數據處理的,例如請求網路信息,文件讀寫等,哪團而handler正是thread和Activity之間的橋梁,負責吧thread得到李嫌橘的信息傳遞給activity,從而完成UI(界面)的刷新。
❺ Android中的Handler詳解以及和Thread的區別
handler主要用於線程間通信,舉一個常見的場景,在一個新彎掘開的thread中請求網路,等待網路請求成功後更新界面。此州鬧和時,由於更新UI的操作不能在新開的thread中完冊盯成,需要handler發送消息到主線程中來執行。
例如:new Thread(new Runnable(){
@override
public void run(){
Object result=queryWeather();
Message message = handler.obtainMessage();
message.obj = result;
handler.sendMessage(0);
}
}).start();
在主線程中定義handler,Handler handler = new Handler(){
@override
public void handleMessage(Message msg){
switch(msg.what){
case 0:
//此處為收到thread發來的消息,在此更新textView
textView.setText(msg.obj.getContent());
break;
}
}
}
大概就是這個用途,手敲的代碼可能會有錯誤,意思應該明白
❻ Android中的Handler詳解以及和Thread的區別
一、Handler的定義:
主要接受子線程發送的數據, 並用此數據配合主線程更新UI.
解釋: 當應用程序啟動時,首先會開啟一個主線程 (也就是UI線程) , 主線程為管理界面中的UI控制項,進行事件分發, 比如說, 你要是點擊一個 Button ,Android會分發事件到Button上,來響應你的操作。 如果此時需要一個耗時的操作,例如: 聯網讀取數據, 或者讀取本地較大的一個文件的時候,你不能把這些操作放在主線程中,,如果你放在主線程中的話,界面會出現假死現象, 如果5秒鍾還沒有完成的話,,會收到Android系統的一個錯誤提示 "強制關閉". 這個時候我們需要把這些耗時的操作,放在一個子線程中,因為子線程涉及到UI更新,,Android主線程是線程不安全的,也就是說,更新UI只能在主線程中更新,子線程中操作是危險的. 這個時候,Handler就出現了.,來解決這個復雜的問題 , 由於Handler運行在主線程中(UI線程中), 它與子線程可以通過Message對象來傳遞數據, 這個時候,Handler就承擔著接受子線程傳過來的(子線程用sedMessage()方法傳弟)Message對象,(裡麵包含數據) , 把這些消息放入主線程隊列中,配合主線程進行更新UI。
二、Handler一些特點
handler可以分發Message對象和Runnable對象到主線程中, 每個Handler實例,都會綁定到創建他的線程中(一般是位於主線程),
它有兩個作用: (1): 安排消息或Runnable 在某個主線程中某個地方執行, (2)安排一個動作在不同的線程中執行
Handler中分發消息的一些方法
[html] view plain
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
以上post類方法允許你排列一個Runnable對象到主線程隊列中,
sendMessage類方法, 允許你安排一個帶數據的Message對象到隊列中,等待更新.
三、Handler實例
(1) 子類需要繼承Hendler類,並重寫handleMessage(Message msg) 方法, 用於接受線程數據
以下為一個實例,它實現的功能為 : 通過線程修改界面Button的內容
[html] view plain
public class MyHandlerActivity extends Activity {
Button button;
MyHandler myHandler;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.handlertest);
button = (Button) findViewById(R.id.button);
myHandler = new MyHandler();
// 當創建一個新的Handler實例時, 它會綁定到當前線程和消息的隊列中,開始分發數據
// Handler有兩個作用, (1) : 定時執行Message和Runnalbe 對象
// (2): 讓一個動作,在不同的線程中執行.
// 它安排消息,用以下方法
// post(Runnable)
// postAtTime(Runnable,long)
// postDelayed(Runnable,long)
// sendEmptyMessage(int)
// sendMessage(Message);
// sendMessageAtTime(Message,long)
// sendMessageDelayed(Message,long)
// 以上方法以 post開頭的允許你處理Runnable對象
//sendMessage()允許你處理Message對象(Message里可以包含數據,)
MyThread m = new MyThread();
new Thread(m).start();
}
/**
* 接受消息,處理消息 ,此Handler會與當前主線程一塊運行
* */
class MyHandler extends Handler {
public MyHandler() {
}
public MyHandler(Looper L) {
super(L);
}
// 子類必須重寫此方法,接受數據
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
Log.d("MyHandler", "handleMessage......");
super.handleMessage(msg);
// 此處可以更新UI
Bundle b = msg.getData();
String color = b.getString("color");
MyHandlerActivity.this.button.append(color);
}
}
class MyThread implements Runnable {
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("thread.......", "mThread........");
Message msg = new Message();
Bundle b = new Bundle();// 存放數據
b.putString("color", "我的");
msg.setData(b);
MyHandlerActivity.this.myHandler.sendMessage(msg); // 向Handler發送消息,更新UI
}
}
}
例外一個案例:
[html] view plain
package com.example.span.view;
import java.util.LinkedList;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Toast;
import com.example.span.view.domain.Block;
/**
* 2013-6-6 上午9:24:58
*
* @author 喬曉松
*/
public class GameView extends View {
public static boolean flag = true;
public static Block block;
public Handler handler;
public static int dir = 2;
public static final int DIRTOP = -1;
public static final int DIRLEFT = -2;
public static final int DIRDOWN = 1;
public static final int DIRRIGHT = 2;
public static int descount = 2;
public Canvas canvas;
public static Food food;
public LinkedList<Point> points = new LinkedList<Point>();
public LinkedList<Point> getPoints() {
return points;
}
public void setPoints(LinkedList<Point> points) {
this.points = points;
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
block = new Block(this);
for (int i = 0; i < 3; i++) {
Point point = new Point(block.getCx(), block.getCy());
block.setCx(block.getCx() - 20);
points.addLast(point);
}
food = new Food(this);
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case DIRLEFT:
if (msg.what + descount != 0) {
descount = -2;
block.moveLeft();
} else {
block.moveRight();
}
break;
case DIRRIGHT:
if (msg.what + descount != 0) {
descount = 2;
block.moveRight();
} else {
block.moveLeft();
}
break;
case DIRTOP:
if (msg.what + descount != 0) {
descount = -1;
block.giveUp();
} else {
block.downLoad();
}
break;
case DIRDOWN:
if (msg.what + descount != 0) {
descount = 1;
block.downLoad();
} else {
block.giveUp();
}
break;
case -3:
Toast.makeText(getContext(), "Game Over", Toast.LENGTH_LONG)
.show();
new AlertDialog.Builder(getContext())
.setTitle("游戲提示")
.setMessage("Game Over")
.setPositiveButton("退出",
new DialogInterface.OnClickListener() {
@Override
public void onClick(
DialogInterface dialog,
int which) {
Thread.currentThread().stop();
}
})
.setNegativeButton("返回菜單",
new DialogInterface.OnClickListener() {
@Override
public void onClick(
DialogInterface dialog,
int which) {
Intent intent = new Intent();
intent.setAction("android.intent.action.MAI");
intent.addCategory("android.intent.category.LAUNCHER");
intent.setFlags(0x10200000);
intent.setComponent(new ComponentName(
"com.example.span",
"com.example.span.SpanActivity"));
getContext().startActivity(intent);
}
}).show();
break;
}
}
};
new Thread(new Runnable() {
@Override
public void run() {
while (flag) {
try {
Thread.sleep(500);
handler.sendEmptyMessage(dir);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
handler.sendEmptyMessage(-3);
}
}).start();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
System.out.println(keyCode);
return super.onKeyDown(keyCode, event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
food.chsw(canvas);
/*
* if (descount == 2) { chsw(); } else { if (points.contains(new
* Point(40, 40))) { System.out.println("吃掉食物了,,.."); } else { chsw(); }
* }
❼ 如何解決空指針異常和 ThreadException 中的錯誤android
在android2.3之後 在主線程首殲中必須使用者悄沖另一個線程 如handler機制,或者非同步任務獲取網路數據運昌
如果訪問網路的操作 必須放在主線程中執行,那麼 在oncreate()中添加
if (GetVersion.GetSystemVersion() > 2.3) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads().detectDiskWrites().detectNetwork()
.penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath()
.build());
}
這樣 高版本中也可以在主線程中執行網路操作了
❽ 在android AndroidManifest.xml文件中怎樣設置訪問網路的許可權
在<manifest標簽下添加語句:
<uses-permission android:name="android.permission.INTERNET"/>
即可申請到訪問網路的許可權
拓展內容:
Android 6.0 運行時許可權的介紹
在保護用戶隱私方面:Android6.0為了更好的保護個人隱私,添加了運行時許可權:分為兩類,一類是Normal Permissions,這類許可權不涉及個人隱私,不需要用戶進行授權,比如手機震動,訪問網路;一類是Dangerous Permissions,這類許可權涉及個人隱私,需要用戶進行授權,比如讀取SD卡,訪問通訊錄等。
在用戶操作方面:當執行敏感操作之前彈出對話框,請求許可權,可以拒絕,可以同意;可以在設置頁面對APP的許可權進行查看,以及對單個許可權進行授權或者解除授權。
❾ Android線程池的使用
在Android中有主線程和子線程的區分。主線程又稱為UI線程,主要是處理一些和界面相關的事情,而子線程主要是用於處理一些耗時比較大的一些任務,例如一些網路操作,IO請求等。如果在主線程中處理這些耗時的任務,則有可能會出現ANR現象(App直接卡死)。
線程池,從名字的表明含義上我們知道線程池就是包含線程的一個池子,它起到新建線程、管理線程、調度線程等作用。
既然Android中已經有了線程的概念,那麼為什麼需要使用線程池呢?我們從兩個方面給出使用線程池的原因。
在Android中線程池就是ThreadPoolExecutor對象。我們先來看一下ThreadPoolExecutor的構造函數。
我們分別說一下當前的幾個參數的含義:
第一個參數corePoolSize為 核心線程數 ,也就是說線程池中至少有這么多的線程,即使存在的這些線程沒有執行任務。但是有一個例外就是,如果在線程池中設置了allowCoreThreadTimeOut為true,那麼在 超時時間(keepAliveTime) 到達後核心線程也會被銷毀。
第二個參數maximumPoolSize為 線程池中的最大線程數 。當活動線程數達到這個數後,後續添加的新任務會被阻塞。
第三個參數keepAliveTime為 線程的保活時間 ,就是說如果線程池中有多於核心線程數的線程,那麼在線程沒有任務的那一刻起開始計時,如果超過了keepAliveTime,還沒有新的任務過來,則該線程就要被銷毀。同時如果設置了allowCoreThreadTimeOut為true,該時間也就是上面第一條所說的 超時時間 。
第四個參數unit為 第三個參數的計時單位 ,有毫秒、秒等。
第五個參數workQueue為 線程池中的任務隊列 ,該隊列持有由execute方法傳遞過來的Runnable對象(Runnable對象就是一個任務)。這個任務隊列的類型是BlockQueue類型,也就是阻塞隊列,當隊列的任務數為0時,取任務的操作會被阻塞;當隊列的任務數滿了(活動線程達到了最大線程數),添加操作就會阻塞。
第哪殲純六個參數threadFactory為 線程工廠 ,當線程池需要創建一個新線程時,使用線程工廠來給線程池提供一個線程。
第七個參數改含handler為 拒絕策略 ,當線程池使用有界隊列時(也就是第五個參數),如果隊列滿了,任務添加到線程池的時候的一個拒絕策略。
可以看到FixedThreadPool的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出FixedThreadPool的幾個特點:
可以看到CacheThreadPool的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出CacheThreadPool的幾個特點:
可以看到ScheledThreadPoolExecutor的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出ScheledThreadPoolExecutor的幾個特點:
可以看到SingleThreadExecutor的構建調用了ThreadPoolExecutor的構造函數。從上面的李咐調用中可以看出SingleThreadExecutor的幾個特點:
❿ 為什麼android在線程中請求網路數據會報錯去掉線程就好了,有沒有大神知道,急!!下面是加 了線程的代碼
Toast.makeText(getApplicationContext(), result, 1).show();
本質是進行UI更新
需要在主線程下調用衫亂
網路訪問的處理結果需要通過handler發送消息
然後在handler內對接收到的不同消陵粗息進行分別處理
handler是運行在主線程下, 可以進尺塌鎮行UI更新