欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Android項(xiàng)目中哪些情況會(huì)出現(xiàn)內(nèi)存泄漏

今天就跟大家聊聊有關(guān)Android項(xiàng)目中哪些情況會(huì)出現(xiàn)內(nèi)存泄漏,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

公司主營(yíng)業(yè)務(wù):網(wǎng)站設(shè)計(jì)制作、成都做網(wǎng)站、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出芒市免費(fèi)做網(wǎng)站回饋大家。

1、單例造成的內(nèi)存泄漏

Android的單例模式非常受開發(fā)者的喜愛,不過使用的不恰當(dāng)?shù)脑捯矔?huì)造成內(nèi)存泄漏。因?yàn)閱卫撵o態(tài)特性使得單例的生命周期和應(yīng)用的生命周期一樣長(zhǎng),這就說明了如果一個(gè)對(duì)象已經(jīng)不需要使用了,而單例對(duì)象還持有該對(duì)象的引用,那么這個(gè)對(duì)象將不能被正常回收,這就導(dǎo)致了內(nèi)存泄漏。

public class SingleInstance {

  private static SingleInstance instance;
  private Context context;

  private SingleInstance(Context context) {
    this.context = context;
  }

  public synchronized static SingleInstance getInstance(Context context) {
    if (instance != null) {
      instance = new SingleInstance(context);
    }
    return instance;
  }
}

這是一個(gè)普通的單例模式,大家都知道,靜態(tài)變量最大的特點(diǎn)是什么,常駐內(nèi)存,也就是說如果你的APP的進(jìn)程沒有沒殺死,它就一直在內(nèi)存中。當(dāng)創(chuàng)建這個(gè)單例的時(shí)候,由于需要傳入一個(gè)Context,所以這個(gè)Context的生命周期的長(zhǎng)短至關(guān)重要:如果傳入的是Activity的Context:當(dāng)這個(gè)Context所對(duì)應(yīng)的Activity退出時(shí),由于該Context和Activity的生命周期一樣長(zhǎng)(Activity間接繼承于Context),所以當(dāng)前Activity退出時(shí)它的內(nèi)存并不會(huì)被回收,因?yàn)閱卫龑?duì)象持有該Activity的引用。

所以正確的單例應(yīng)該為這種姿勢(shì):

public class SingleInstance {

  private static SingleInstance instance;
  private Context context;

  private SingleInstance(Context context) {
    this.context = context.getApplicationContext();
  }

  public synchronized static SingleInstance getInstance(Context context) {
    if (instance != null) {
      instance = new SingleInstance(context);
    }
    return instance;
  }
}

這樣不管傳入什么Context最終將使用Application的Context,而單例的生命周期和應(yīng)用的一樣長(zhǎng),這樣就防止了內(nèi)存泄漏。

2、非靜態(tài)內(nèi)部類(比如內(nèi)部類、匿名內(nèi)部類)創(chuàng)建靜態(tài)實(shí)例造成的內(nèi)存泄漏

有的時(shí)候我們可能會(huì)在啟動(dòng)頻繁的Activity中,為了避免重復(fù)創(chuàng)建相同的數(shù)據(jù)資源,會(huì)出現(xiàn)這種寫法:

public class MainActivity extends AppCompatActivity {

  private InnerClass innerClass;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if(innerClass == null){
      innerClass = new InnerClass();
    }
  }

  class InnerClass{

  }
}

這樣就在Activity內(nèi)部創(chuàng)建了一個(gè)非靜態(tài)內(nèi)部類的單例,每次啟動(dòng)Activity時(shí)都會(huì)使用該單例的數(shù)據(jù),這樣雖然避免了資源的重復(fù)創(chuàng)建,不過這種寫法卻會(huì)造成內(nèi)存泄漏,因?yàn)榉庆o態(tài)內(nèi)部類默認(rèn)會(huì)持有外部類的引用,而又使用了該非靜態(tài)內(nèi)部類創(chuàng)建了一個(gè)靜態(tài)的實(shí)例,該實(shí)例的生命周期和應(yīng)用的一樣長(zhǎng),這就導(dǎo)致了該靜態(tài)實(shí)例一直會(huì)持有該Activity的引用,導(dǎo)致Activity的內(nèi)存資源不能正常回收。

正確的做法為:將該內(nèi)部類設(shè)為靜態(tài)內(nèi)部類或?qū)⒃搩?nèi)部類抽取出來封裝成一個(gè)單例,如果需要使用Context,請(qǐng)使用ApplicationContext 。

3、Handler造成的內(nèi)存泄漏

Handler的使用造成的內(nèi)存泄漏問題應(yīng)該說最為常見了,平時(shí)在處理網(wǎng)絡(luò)任務(wù)或者封裝一些請(qǐng)求回調(diào)等api都應(yīng)該會(huì)借助Handler來處理,對(duì)于Handler的使用代碼編寫一不規(guī)范即有可能造成內(nèi)存泄漏,如下示例:

public class MainActivity extends AppCompatActivity {

  private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      //...

    }
  };

  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    loadData();

  }

  private void loadData(){
    //...request
    Message message = Message.obtain();
    mHandler.sendMessage(message);
  }
}

這種創(chuàng)建Handler的方式會(huì)造成內(nèi)存泄漏,由于mHandler是Handler的非靜態(tài)匿名內(nèi)部類的實(shí)例,所以它持有外部類Activity的引用,我們知道消息隊(duì)列是在一個(gè)Looper線程中不斷輪詢處理消息,那么當(dāng)這個(gè)Activity退出時(shí)消息隊(duì)列中還有未處理的消息或者正在處理消息,而消息隊(duì)列中的Message持有mHandler實(shí)例的引用,mHandler又持有Activity的引用,所以導(dǎo)致該Activity的內(nèi)存資源無法及時(shí)回收,引發(fā)內(nèi)存泄漏,所以另外一種做法為,用軟引用:

public class MainActivity extends AppCompatActivity {

  private MyHandler mHandler = new MyHandler(this);
  private TextView mTextView ;

  private static class MyHandler extends Handler {

    private WeakReference<Context> reference;
    public MyHandler(Context context) {
      reference = new WeakReference<>(context);
    }

    @Override
    public void handleMessage(Message msg) {

      MainActivity activity = (MainActivity) reference.get();

      if(activity != null){
        activity.mTextView.setText("");
      }
    }
  }



  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mTextView = (TextView)findViewById(R.id.textview);
    loadData();
  }



  private void loadData() {

    //...request
    Message message = Message.obtain();
    mHandler.sendMessage(message);
  }
}

創(chuàng)建一個(gè)靜態(tài)Handler內(nèi)部類,然后對(duì)Handler持有的對(duì)象使用弱引用,這樣在回收時(shí)也可以回收Handler持有的對(duì)象,這樣雖然避免了Activity泄漏,不過Looper線程的消息隊(duì)列中還是可能會(huì)有待處理的消息,所以我們?cè)贏ctivity的Destroy時(shí)或者Stop時(shí)應(yīng)該移除消息隊(duì)列中的消息,更準(zhǔn)確的做法如下:

public class MainActivity extends AppCompatActivity {

  private MyHandler mHandler = new MyHandler(this);
  private TextView mTextView ;
  private static class MyHandler extends Handler {
    private WeakReference<Context> reference;
    public MyHandler(Context context) {
      reference = new WeakReference<>(context);
    }

    @Override
    public void handleMessage(Message msg) {
      MainActivity activity = (MainActivity) reference.get();
      if(activity != null){
        activity.mTextView.setText("");
      }
    }
  }



  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mTextView = (TextView)findViewById(R.id.textview);
    loadData();
  }


//加載網(wǎng)絡(luò)數(shù)據(jù)的回調(diào)
  private void loadData() {
    //...request
    Message message = Message.obtain();
    mHandler.sendMessage(message);
  }


  @Override
  protected void onDestroy() {
    super.onDestroy();
    //移除消息隊(duì)列和回調(diào)
    mHandler.removeCallbacksAndMessages(null);
  }
}

使用mHandler.removeCallbacksAndMessages(null);是移除消息隊(duì)列中所有消息和所有的Runnable。當(dāng)然也可以使用mHandler.removeCallbacks();或mHandler.removeMessages();來移除指定的Runnable和Message。

當(dāng)然簡(jiǎn)單點(diǎn),也可以直接這樣

 @Override
  protected void onDestroy() {
    super.onDestroy();
    //移除消息隊(duì)列和回調(diào)
    mHandler.removeCallbacksAndMessages(null);
  }

親測(cè)試,有效。

4、線程造成的內(nèi)存泄漏

對(duì)于線程造成的內(nèi)存泄漏,也是平時(shí)比較常見的,如下這兩個(gè)示例可能每個(gè)人都這樣寫過:

//——————test1
    new AsyncTask<Void, Void, Void>() {
      @Override
      protected Void doInBackground(Void... params) {
        SystemClock.sleep(10000);
        return null;
      }
    }.execute();

//——————test2
    new Thread(new Runnable() {
      @Override
      public void run() {
        SystemClock.sleep(10000);
      }
    }).start();

上面的異步任務(wù)和Runnable都是一個(gè)匿名內(nèi)部類,因此它們對(duì)當(dāng)前Activity都有一個(gè)隱式引用。如果Activity在銷毀之前,任務(wù)還未完成, 那么將導(dǎo)致Activity的內(nèi)存資源無法回收,造成內(nèi)存泄漏。正確的做法還是使用靜態(tài)內(nèi)部類的方式,如下:

static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
    private WeakReference<Context> weakReference;
    public MyAsyncTask(Context context) {
      weakReference = new WeakReference<>(context);
    }


    @Override
    protected Void doInBackground(Void... params) {
      SystemClock.sleep(10000);
      return null;
    }



    @Override
    protected void onPostExecute(Void aVoid) {
      super.onPostExecute(aVoid);
      MainActivity activity = (MainActivity) weakReference.get();
      if (activity != null) {
        //...
      }
    }
  }

  static class MyRunnable implements Runnable{
    @Override
    public void run() {
      SystemClock.sleep(10000);
    }
  }
//——————

  new Thread(new MyRunnable()).start();

  new MyAsyncTask(this).execute();

這樣就避免了Activity的內(nèi)存資源泄漏,當(dāng)然在Activity銷毀時(shí)候也應(yīng)該取消相應(yīng)的任務(wù)AsyncTask::cancel(),避免任務(wù)在后臺(tái)執(zhí)行浪費(fèi)資源。

5、資源未關(guān)閉造成的內(nèi)存泄漏

對(duì)于使用了BraodcastReceiver,ContentObserver,F(xiàn)ile,Cursor,Stream,Bitmap等資源的使用,應(yīng)該在Activity銷毀時(shí)及時(shí)關(guān)閉或者注銷,否則這些資源將不會(huì)被回收,造成內(nèi)存泄漏。

看完上述內(nèi)容,你們對(duì)Android項(xiàng)目中哪些情況會(huì)出現(xiàn)內(nèi)存泄漏有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。

網(wǎng)站名稱:Android項(xiàng)目中哪些情況會(huì)出現(xiàn)內(nèi)存泄漏
鏈接地址:http://chinadenli.net/article14/jpsgde.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃網(wǎng)站收錄ChatGPT電子商務(wù)移動(dòng)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名